The aim of these exercises is to continue making sure you’re comfortable with handling multivariate data. In this chapter’s, you’ll focus on analyses based on dissimilarities/distances, including fitting linear models to these kinds of response variables.

For each of the examples below, you should follow the sequence we’ve used previously, as far as it’s sensible:

  1. What is the biological question?

  2. Is the predictor continuous or categorical?

  3. Write out the linear model corresponding to this question.

  4. What distribution do you expect the response variable to follow?

  5. What are the assumptions behind the statistical model you’ll fit?

    1. Are those assumptions satisfied?
  6. Fit the model

    1. How will you assess whether the model fits well?

    2. Can you detect an effect of the predictors?

    3. How do you measure the effect?

  7. What do you conclude (including any cautions)


A

Dixon et al. (2018) focused on assemblages of reptiles in forests and woodlands of southeastern Australia, with a particular interest in relationships between these assemblages and the fire history of the landscape. They identified 81 sites that varied in time since fire, from 6 months to >96 y. Rather than a continuum, three categories of time since fire were used, 0.5-2y, 6-12y, and >96y. Sites were also classified according to habitat.

Reptile assemblages were sampled with a range of methods, including visual surveys and camera traps, to give counts of 20 reptiles, whose abundance ranged from 0-1 to 0-126, depending on species.

Data are available from dryad, as Rep_abund.csv. You’ll want to focus on the columns with reptile numbers, and the one with the fire history (tsf). For convenience, we’ve extracted those data as dixonbiota.csv

Start by having a quick look at the data.

Rows: 79 Columns: 22── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr  (2): site, tsf
dbl (20): adup, aplat, amur, amac, aram, dcor, ecun, esax, eul, htal, ldel, lgui, lwhi, ppor, pent, pspe, ptex, rdie, tnig, vros
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

The file is pretty straightforward, with tsf being the fire category, and columns 3-22 each representing one reptile taxon.

Suppose you think of a reptile assemblage as simply the species that are present, regardless of how common they are. What would you conclude about the infuence of time since fire now?

Repeat the preceding analysis after creating a new data file that is presence-absence only.

Run 0 stress 0.1404128 
Run 1 stress 0.140413 
... Procrustes: rmse 0.000158617  max resid 0.0009441077 
... Similar to previous best
Run 2 stress 0.1489204 
Run 3 stress 0.1448005 
Run 4 stress 0.1486182 
Run 5 stress 0.1453965 
Run 6 stress 0.1418091 
Run 7 stress 0.1415816 
Run 8 stress 0.1481748 
Run 9 stress 0.1418881 
Run 10 stress 0.1404115 
... New best solution
... Procrustes: rmse 0.0004234926  max resid 0.002436781 
... Similar to previous best
Run 11 stress 0.1488108 
Run 12 stress 0.1482426 
Run 13 stress 0.1419245 
Run 14 stress 0.1590438 
Run 15 stress 0.143286 
Run 16 stress 0.1486203 
Run 17 stress 0.1405587 
... Procrustes: rmse 0.01449226  max resid 0.08640004 
Run 18 stress 0.1486316 
Run 19 stress 0.1405592 
... Procrustes: rmse 0.01479786  max resid 0.08730948 
Run 20 stress 0.1405595 
... Procrustes: rmse 0.01483792  max resid 0.08736059 
Run 21 stress 0.1404114 
... New best solution
... Procrustes: rmse 0.002731297  max resid 0.02192069 
Run 22 stress 0.1496581 
Run 23 stress 0.1416846 
Run 24 stress 0.1405862 
... Procrustes: rmse 0.01597208  max resid 0.09180616 
Run 25 stress 0.1461628 
Run 26 stress 0.1404123 
... Procrustes: rmse 0.000245968  max resid 0.001978068 
... Similar to previous best
Run 27 stress 0.1405596 
... Procrustes: rmse 0.01457381  max resid 0.08827165 
Run 28 stress 0.1404116 
... Procrustes: rmse 0.0002275687  max resid 0.001455665 
... Similar to previous best
Run 29 stress 0.1478219 
Run 30 stress 0.1438487 
Run 31 stress 0.1404119 
... Procrustes: rmse 0.0001425049  max resid 0.001044504 
... Similar to previous best
Run 32 stress 0.1478221 
Run 33 stress 0.141641 
Run 34 stress 0.1414341 
Run 35 stress 0.1422857 
Run 36 stress 0.1487658 
Run 37 stress 0.1486133 
Run 38 stress 0.1502159 
Run 39 stress 0.1486756 
Run 40 stress 0.1404122 
... Procrustes: rmse 0.0002283066  max resid 0.001565205 
... Similar to previous best
*** Best solution repeated 4 times


Call:
metaMDS(comm = df1.jac, k = 3, try = 40, trymax = 80, autotransform = FALSE,      maxit = 200) 

global Multidimensional Scaling using monoMDS

Data:     df1.jac 
Distance: binary jaccard 

Dimensions: 3 
Stress:     0.1404114 
Stress type 1, weak ties
Best solution was repeated 4 times in 40 tries
The best solution was from try 21 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: scores missing

Run 0 stress 0.2009509 
Run 1 stress 0.2019149 
Run 2 stress 0.2011657 
... Procrustes: rmse 0.006416695  max resid 0.0398645 
Run 3 stress 0.202576 
Run 4 stress 0.2284835 
Run 5 stress 0.2197434 
Run 6 stress 0.2011646 
... Procrustes: rmse 0.006850207  max resid 0.03839815 
Run 7 stress 0.2204112 
Run 8 stress 0.215058 
Run 9 stress 0.203002 
Run 10 stress 0.2143484 
Run 11 stress 0.2104918 
Run 12 stress 0.2180894 
Run 13 stress 0.2279185 
Run 14 stress 0.2071546 
Run 15 stress 0.2160939 
Run 16 stress 0.2164477 
Run 17 stress 0.2108417 
Run 18 stress 0.2097709 
Run 19 stress 0.2079378 
Run 20 stress 0.2138375 
Run 21 stress 0.2120034 
Run 22 stress 0.2115225 
Run 23 stress 0.215718 
Run 24 stress 0.2057211 
Run 25 stress 0.2030018 
Run 26 stress 0.213385 
Run 27 stress 0.2285741 
Run 28 stress 0.2289543 
Run 29 stress 0.2178744 
Run 30 stress 0.208991 
Run 31 stress 0.2135402 
Run 32 stress 0.20361 
Run 33 stress 0.2156126 
Run 34 stress 0.2146268 
Run 35 stress 0.2167606 
Run 36 stress 0.2274825 
Run 37 stress 0.202578 
Run 38 stress 0.2036086 
Run 39 stress 0.2171294 
Run 40 stress 0.2366921 
Run 41 stress 0.2011785 
... Procrustes: rmse 0.006149074  max resid 0.03876166 
Run 42 stress 0.218512 
Run 43 stress 0.2020987 
Run 44 stress 0.2068717 
Run 45 stress 0.2041772 
Run 46 stress 0.203832 
Run 47 stress 0.2272148 
Run 48 stress 0.2035363 
Run 49 stress 0.2074059 
Run 50 stress 0.2174067 
Run 51 stress 0.2098787 
Run 52 stress 0.2074132 
Run 53 stress 0.2011648 
... Procrustes: rmse 0.006869384  max resid 0.03837032 
Run 54 stress 0.2133796 
Run 55 stress 0.2139331 
Run 56 stress 0.2112664 
Run 57 stress 0.226952 
Run 58 stress 0.2011782 
... Procrustes: rmse 0.006123098  max resid 0.03888408 
Run 59 stress 0.2119751 
Run 60 stress 0.2133246 
Run 61 stress 0.2134668 
Run 62 stress 0.2045553 
Run 63 stress 0.2084428 
Run 64 stress 0.2019056 
Run 65 stress 0.2041934 
Run 66 stress 0.2144476 
Run 67 stress 0.2068721 
Run 68 stress 0.2128513 
Run 69 stress 0.2069873 
Run 70 stress 0.2116038 
Run 71 stress 0.2187148 
Run 72 stress 0.2030068 
Run 73 stress 0.2078151 
Run 74 stress 0.2011768 
... Procrustes: rmse 0.005962949  max resid 0.03913871 
Run 75 stress 0.2056871 
Run 76 stress 0.2011778 
... Procrustes: rmse 0.006066117  max resid 0.03889517 
Run 77 stress 0.2177676 
Run 78 stress 0.2127882 
Run 79 stress 0.2111792 
Run 80 stress 0.2014982 
*** Best solution was not repeated -- monoMDS stopping criteria:
    12: no. of iterations >= maxit
    68: stress ratio > sratmax


Call:
metaMDS(comm = df1.jac, k = 2, try = 40, trymax = 80, autotransform = FALSE,      maxit = 200) 

global Multidimensional Scaling using monoMDS

Data:     df1.jac 
Distance: binary jaccard 

Dimensions: 2 
Stress:     0.2009509 
Stress type 1, weak ties
Best solution was not repeated after 80 tries
The best solution was from try 0 (metric scaling or null solution)
Scaling: centring, PC rotation, halfchange scaling 
Species: scores missing

Marginal decision here - stress just over 0.2 for k=2, so might be OK. Stress good for k=3, but 2-d MDS usually better for reporting or showing to audience

Unburned sites separate very clearly on MDS1. Pattern clearer than with abundances included

Do permanova including tsf

Permutation test for adonis under reduced model
Terms added sequentially (first to last)
Permutation: free
Number of permutations: 999

adonis2(formula = df1.jac ~ tsf, data = df, permutations = 999)
         Df SumOfSqs      R2      F Pr(>F)    
tsf       2   3.7853 0.20678 9.9057  0.001 ***
Residual 76  14.5210 0.79322                  
Total    78  18.3062 1.00000                  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Clear fire signal

Extension activity

Dixon and her colleagues also recorded a range of habitat variables, which we’ve collected for you in dixonenv.csv

Rows: 79 Columns: 14── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr  (4): site, tsf, veg, aspect
dbl (10): lcwd, shrcov, grcov, litcov, litdep, rocks, elev, warm, cold, twi
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

They recorded Coarse Woody Debris, which was long-transformed, litter cover (litcov), % cover of groundcover (grcov), and % cover of shrubs (shrcov), and rock cover. In the original paper, Dixon et al. were comfortable that these predictors weren’t correlated.

mvabund

Error in model.frame.default(formula = dfmv ~ dixonenv$tsf + dixonenv$lcwd +  : 
  variable lengths differ (found for 'dixonenv$tsf')

B Simple MDS & Permanova

Let’s return to the Hutto and Barrett (2021) example from the Chapter 15 exercises. There, we used similarity-based analyses to explore the relationship between frog assemblages in ponds and the degree of urbanization surrounding. This seems a question that could just as easily be examined using distances or dissimilarities.

Return to the data and assess whether frog assemblages (using the standardized abundance scale or presence-absence) differ with urbanization.

Did your conclusions differ from those obtained using RDA?

Rows: 50 Columns: 14── Column specification ──────────────────────────────────────────────────────────────────────
Delimiter: ","
chr  (1): type
dbl (13): Site, ACRE, BAME, BFOW, GCAR, HCIN, HVER, LCAT, LCLA, LPAL, LSPH, PCRU, PFER
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

The explanation of the variables is in the previous chapter’s exercises.

Run 0 stress 0.196708 
Run 1 stress 0.1877627 
... New best solution
... Procrustes: rmse 0.06210972  max resid 0.2289889 
Run 2 stress 0.1965252 
Run 3 stress 0.2177645 
Run 4 stress 0.1983645 
Run 5 stress 0.2034451 
Run 6 stress 0.2052112 
Run 7 stress 0.1877626 
... New best solution
... Procrustes: rmse 0.0001156879  max resid 0.0003505044 
... Similar to previous best
Run 8 stress 0.185584 
... New best solution
... Procrustes: rmse 0.07743106  max resid 0.5021775 
Run 9 stress 0.1992463 
Run 10 stress 0.1974204 
Run 11 stress 0.1946875 
Run 12 stress 0.1862779 
Run 13 stress 0.1863292 
Run 14 stress 0.2005585 
Run 15 stress 0.1920873 
Run 16 stress 0.1875597 
Run 17 stress 0.1964527 
Run 18 stress 0.1920872 
Run 19 stress 0.1977907 
Run 20 stress 0.2167665 
Run 21 stress 0.1875595 
Run 22 stress 0.1929107 
Run 23 stress 0.1975661 
Run 24 stress 0.186278 
Run 25 stress 0.1875598 
Run 26 stress 0.1960212 
Run 27 stress 0.1991282 
Run 28 stress 0.1975497 
Run 29 stress 0.185397 
... New best solution
... Procrustes: rmse 0.02114207  max resid 0.1079972 
Run 30 stress 0.1969418 
Run 31 stress 0.186278 
Run 32 stress 0.1862238 
Run 33 stress 0.1877806 
Run 34 stress 0.1919384 
Run 35 stress 0.1967647 
Run 36 stress 0.2073798 
Run 37 stress 0.1888207 
Run 38 stress 0.2054248 
Run 39 stress 0.1874611 
Run 40 stress 0.1862237 
Run 41 stress 0.186278 
Run 42 stress 0.1888251 
Run 43 stress 0.1937375 
Run 44 stress 0.1862237 
Run 45 stress 0.1963067 
Run 46 stress 0.1862237 
Run 47 stress 0.1854373 
... Procrustes: rmse 0.009296219  max resid 0.0491063 
Run 48 stress 0.1920872 
Run 49 stress 0.1875595 
Run 50 stress 0.1853641 
... New best solution
... Procrustes: rmse 0.001953553  max resid 0.00909663 
... Similar to previous best
*** Best solution repeated 1 times


Call:
metaMDS(comm = df1.bc, k = 2, try = 40, trymax = 80, autotransform = FALSE,      maxit = 200) 

global Multidimensional Scaling using monoMDS

Data:     df1.bc 
Distance: bray 

Dimensions: 2 
Stress:     0.1853641 
Stress type 1, weak ties
Best solution was repeated 1 time in 50 tries
The best solution was from try 50 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: scores missing

Run 0 stress 0.129187 
Run 1 stress 0.1291859 
... New best solution
... Procrustes: rmse 0.0008388266  max resid 0.00496375 
... Similar to previous best
Run 2 stress 0.1402078 
Run 3 stress 0.1308799 
Run 4 stress 0.1289613 
... New best solution
... Procrustes: rmse 0.01088561  max resid 0.05621761 
Run 5 stress 0.129186 
... Procrustes: rmse 0.01089164  max resid 0.05582815 
Run 6 stress 0.1289616 
... Procrustes: rmse 0.0002674815  max resid 0.001155959 
... Similar to previous best
Run 7 stress 0.1380881 
Run 8 stress 0.1425061 
Run 9 stress 0.1395557 
Run 10 stress 0.1291859 
... Procrustes: rmse 0.01090439  max resid 0.05603889 
Run 11 stress 0.1291861 
... Procrustes: rmse 0.01047698  max resid 0.0544579 
Run 12 stress 0.1380864 
Run 13 stress 0.12921 
... Procrustes: rmse 0.01243608  max resid 0.06398953 
Run 14 stress 0.1291867 
... Procrustes: rmse 0.01108112  max resid 0.05658361 
Run 15 stress 0.1380875 
Run 16 stress 0.1289612 
... New best solution
... Procrustes: rmse 0.0001897893  max resid 0.001008599 
... Similar to previous best
Run 17 stress 0.1291861 
... Procrustes: rmse 0.01047209  max resid 0.05451001 
Run 18 stress 0.1384298 
Run 19 stress 0.1291858 
... Procrustes: rmse 0.01085358  max resid 0.05610837 
Run 20 stress 0.1289617 
... Procrustes: rmse 0.0005107488  max resid 0.002356854 
... Similar to previous best
Run 21 stress 0.129192 
... Procrustes: rmse 0.01049379  max resid 0.05482609 
Run 22 stress 0.1291861 
... Procrustes: rmse 0.01090769  max resid 0.05651704 
Run 23 stress 0.1291858 
... Procrustes: rmse 0.01084092  max resid 0.05603118 
Run 24 stress 0.1291603 
... Procrustes: rmse 0.009742854  max resid 0.05179386 
Run 25 stress 0.1291861 
... Procrustes: rmse 0.01048144  max resid 0.05456092 
Run 26 stress 0.1291857 
... Procrustes: rmse 0.01077451  max resid 0.05553841 
Run 27 stress 0.1380876 
Run 28 stress 0.1402635 
Run 29 stress 0.1384275 
Run 30 stress 0.1291864 
... Procrustes: rmse 0.01045087  max resid 0.05448513 
Run 31 stress 0.129186 
... Procrustes: rmse 0.01090378  max resid 0.0564044 
Run 32 stress 0.1291859 
... Procrustes: rmse 0.01083027  max resid 0.0561575 
Run 33 stress 0.1380913 
Run 34 stress 0.1291855 
... Procrustes: rmse 0.01069769  max resid 0.05541034 
Run 35 stress 0.1383999 
Run 36 stress 0.1289618 
... Procrustes: rmse 0.0005305334  max resid 0.002504772 
... Similar to previous best
Run 37 stress 0.1291859 
... Procrustes: rmse 0.01084244  max resid 0.05590108 
Run 38 stress 0.1289621 
... Procrustes: rmse 0.0006163776  max resid 0.002721091 
... Similar to previous best
Run 39 stress 0.1291858 
... Procrustes: rmse 0.01057936  max resid 0.05497957 
Run 40 stress 0.1291858 
... Procrustes: rmse 0.01050048  max resid 0.05461872 
*** Best solution repeated 4 times


Call:
metaMDS(comm = df1.bc, k = 3, try = 40, trymax = 80, autotransform = FALSE,      maxit = 200) 

global Multidimensional Scaling using monoMDS

Data:     df1.bc 
Distance: bray 

Dimensions: 3 
Stress:     0.1289612 
Stress type 1, weak ties
Best solution was repeated 4 times in 40 tries
The best solution was from try 16 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: scores missing

2-d is acceptable

Permutation test for adonis under reduced model
Terms added sequentially (first to last)
Permutation: free
Number of permutations: 999

adonis2(formula = df1.bc ~ type, data = df, permutations = 999)
         Df SumOfSqs      R2      F Pr(>F)  
type      2    0.912 0.07281 1.7669  0.034 *
Residual 45   11.614 0.92719                
Total    47   12.526 1.00000                
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Permanova detects a difference; MDS plot suggests low urbanization may be different from the other two, though worth looking at dispersion as well, as spread of this type is less than the other two on plot

Repeat analysis with presence-absence

df1.jac <- vegdist(df1,binary=TRUE,method=‘jaccard’)

Run 0 stress 0.1551612 
Run 1 stress 0.1538244 
... New best solution
... Procrustes: rmse 0.01653307  max resid 0.06524188 
Run 2 stress 0.1808491 
Run 3 stress 0.1646706 
Run 4 stress 0.1901198 
Run 5 stress 0.1908161 
Run 6 stress 0.1607835 
Run 7 stress 0.1961593 
Run 8 stress 0.163888 
Run 9 stress 0.158713 
Run 10 stress 0.1551611 
Run 11 stress 0.1728782 
Run 12 stress 0.1627091 
Run 13 stress 0.1602264 
Run 14 stress 0.1538803 
... Procrustes: rmse 0.0179707  max resid 0.07573361 
Run 15 stress 0.1609335 
Run 16 stress 0.1646707 
Run 17 stress 0.1945193 
Run 18 stress 0.1837141 
Run 19 stress 0.1669303 
Run 20 stress 0.1585798 
Run 21 stress 0.1630282 
Run 22 stress 0.15858 
Run 23 stress 0.1585799 
Run 24 stress 0.1734741 
Run 25 stress 0.1630923 
Run 26 stress 0.1585799 
Run 27 stress 0.1602583 
Run 28 stress 0.15858 
Run 29 stress 0.1752544 
Run 30 stress 0.1784224 
Run 31 stress 0.1609031 
Run 32 stress 0.1553998 
Run 33 stress 0.1707427 
Run 34 stress 0.1604495 
Run 35 stress 0.1623918 
Run 36 stress 0.1646706 
Run 37 stress 0.1781197 
Run 38 stress 0.1622267 
Run 39 stress 0.1669302 
Run 40 stress 0.1629465 
Run 41 stress 0.1627091 
Run 42 stress 0.1760835 
Run 43 stress 0.1538804 
... Procrustes: rmse 0.01791116  max resid 0.07567211 
Run 44 stress 0.1603052 
Run 45 stress 0.1666163 
Run 46 stress 0.1538248 
... Procrustes: rmse 0.0003646799  max resid 0.001890428 
... Similar to previous best
*** Best solution repeated 1 times


Call:
metaMDS(comm = df1.jac, k = 2, try = 40, trymax = 80, autotransform = FALSE,      maxit = 200) 

global Multidimensional Scaling using monoMDS

Data:     df1.jac 
Distance: binary jaccard 

Dimensions: 2 
Stress:     0.1538244 
Stress type 1, weak ties
Best solution was repeated 1 time in 46 tries
The best solution was from try 1 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: scores missing

Run 0 stress 0.09466813 
Run 1 stress 0.09466799 
... New best solution
... Procrustes: rmse 0.0005113888  max resid 0.002601587 
... Similar to previous best
Run 2 stress 0.1116796 
Run 3 stress 0.09466791 
... New best solution
... Procrustes: rmse 5.140713e-05  max resid 0.0001769429 
... Similar to previous best
Run 4 stress 0.09466788 
... New best solution
... Procrustes: rmse 6.431395e-05  max resid 0.0002594411 
... Similar to previous best
Run 5 stress 0.09466814 
... Procrustes: rmse 0.0001741567  max resid 0.0005987574 
... Similar to previous best
Run 6 stress 0.109059 
Run 7 stress 0.09466798 
... Procrustes: rmse 8.15394e-05  max resid 0.0003917043 
... Similar to previous best
Run 8 stress 0.09466792 
... Procrustes: rmse 8.950007e-05  max resid 0.0003379089 
... Similar to previous best
Run 9 stress 0.09466804 
... Procrustes: rmse 0.0001189413  max resid 0.0003712925 
... Similar to previous best
Run 10 stress 0.1004901 
Run 11 stress 0.09466837 
... Procrustes: rmse 0.0002451238  max resid 0.001009793 
... Similar to previous best
Run 12 stress 0.09694634 
Run 13 stress 0.09466805 
... Procrustes: rmse 0.0001311181  max resid 0.0006621851 
... Similar to previous best
Run 14 stress 0.09466838 
... Procrustes: rmse 0.0002467991  max resid 0.00110516 
... Similar to previous best
Run 15 stress 0.1097138 
Run 16 stress 0.09466796 
... Procrustes: rmse 0.0001191739  max resid 0.0005138992 
... Similar to previous best
Run 17 stress 0.09466843 
... Procrustes: rmse 0.0005603326  max resid 0.002919388 
... Similar to previous best
Run 18 stress 0.1005045 
Run 19 stress 0.09466785 
... New best solution
... Procrustes: rmse 4.336385e-05  max resid 0.0001341018 
... Similar to previous best
Run 20 stress 0.09466823 
... Procrustes: rmse 0.0004406253  max resid 0.00239166 
... Similar to previous best
Run 21 stress 0.09466821 
... Procrustes: rmse 0.0002307082  max resid 0.0007713212 
... Similar to previous best
Run 22 stress 0.09693811 
Run 23 stress 0.09466805 
... Procrustes: rmse 0.0001145164  max resid 0.0005228285 
... Similar to previous best
Run 24 stress 0.09466802 
... Procrustes: rmse 0.0001210626  max resid 0.0004425707 
... Similar to previous best
Run 25 stress 0.1005046 
Run 26 stress 0.09466798 
... Procrustes: rmse 0.000102713  max resid 0.0004059971 
... Similar to previous best
Run 27 stress 0.09466796 
... Procrustes: rmse 8.304787e-05  max resid 0.000343865 
... Similar to previous best
Run 28 stress 0.1090607 
Run 29 stress 0.1097141 
Run 30 stress 0.1131481 
Run 31 stress 0.09693847 
Run 32 stress 0.1131483 
Run 33 stress 0.09466825 
... Procrustes: rmse 0.0002105948  max resid 0.0008409997 
... Similar to previous best
Run 34 stress 0.1116801 
Run 35 stress 0.09466791 
... Procrustes: rmse 0.0001849118  max resid 0.0006962707 
... Similar to previous best
Run 36 stress 0.09466793 
... Procrustes: rmse 0.0001164267  max resid 0.0003992448 
... Similar to previous best
Run 37 stress 0.09693871 
Run 38 stress 0.09466835 
... Procrustes: rmse 0.0002585436  max resid 0.001174372 
... Similar to previous best
Run 39 stress 0.1005044 
Run 40 stress 0.09693812 
*** Best solution repeated 11 times


Call:
metaMDS(comm = df1.jac, k = 3, try = 40, trymax = 80, autotransform = FALSE,      maxit = 200) 

global Multidimensional Scaling using monoMDS

Data:     df1.jac 
Distance: binary jaccard 

Dimensions: 3 
Stress:     0.09466785 
Stress type 1, weak ties
Best solution was repeated 11 times in 40 tries
The best solution was from try 19 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: scores missing

Again, stress OK with 2D, good with 3D. Look at 2D first

Permutation test for adonis under reduced model
Terms added sequentially (first to last)
Permutation: free
Number of permutations: 999

adonis2(formula = df1.jac ~ type, data = df, permutations = 999)
         Df SumOfSqs      R2      F Pr(>F)
type      2   0.4525 0.04389 1.0328  0.404
Residual 45   9.8587 0.95611              
Total    47  10.3112 1.00000              

No separation seen on Presence-Absence

C

Griffen et al. (2019) examined the oral microbiome of humans, with a focus on the effects of HIV and AntiRetroviral therapy (ART) on this microbiome. They described the microbiome of 341 patients, who fell into one of two categories: HIV-, and HIV+ with ART. They also matched their samples as far as possible for sex, along with other conditions that can influence oral microbiomes (Candida infection, current smoking). We’ll use their records for these other categories as well. There were more HIV+ than - subjects, but within these groups, approximately equal numbers of two sexes, two Candida infection status, and two smoking categories.

The bacteriome was recorded separately using 16S RNA sequencing, which overed just over 600 taxa.

The data are available from their paper, as two Excel files in the supplementary information. The metadata gives HIV status, and a raft of demographic information. We’ll just work with HIV, sex, Candida, and current smoking. A second sheet has the bacteriome. The code chunk below reads this file (from a Downloads folder - you’ll need to modify the file location). It also screens the file for any bacterial taxa that were not present in this particular study, which reduces the bacterial taxa to 599.

New names:

Use a dissimilarity based approach to assess the combined effects of HIV-ART, sex, Candida infection, and current smoking on the bacteriome

Do these factors act independently on the bacteriome?

Which effects are largest (use some graphical methods)?

First steps: Think about standardization and which distance measure you’ll use. Bray-Curtis seems common for these kind of data, and and counts of different taxa vary widely.

Run factorial model using permanova, based on B-C

Permutation test for adonis under reduced model
Terms added sequentially (first to last)
Permutation: free
Number of permutations: 999

adonis2(formula = df1s.bc ~ HIV * candida * gender * smoking_current, data = df, permutations = 999)
                                    Df SumOfSqs      R2      F Pr(>F)    
HIV                                  1    1.369 0.01250 4.3776  0.001 ***
candida                              1    1.461 0.01333 4.6694  0.001 ***
gender                               1    0.492 0.00449 1.5737  0.016 *  
smoking_current                      1    1.111 0.01014 3.5513  0.001 ***
HIV:candida                          1    0.318 0.00290 1.0151  0.375    
HIV:gender                           1    0.354 0.00324 1.1332  0.214    
candida:gender                       1    0.257 0.00234 0.8202  0.830    
HIV:smoking_current                  1    0.269 0.00245 0.8584  0.773    
candida:smoking_current              1    0.344 0.00314 1.0989  0.250    
gender:smoking_current               1    0.394 0.00360 1.2602  0.096 .  
HIV:candida:gender                   1    0.349 0.00319 1.1164  0.235    
HIV:candida:smoking_current          1    0.280 0.00255 0.8943  0.679    
HIV:gender:smoking_current           1    0.265 0.00242 0.8463  0.784    
candida:gender:smoking_current       1    0.254 0.00232 0.8110  0.873    
HIV:candida:gender:smoking_current   1    0.362 0.00330 1.1562  0.198    
Residual                           325  101.664 0.92809                  
Total                              340  109.541 1.00000                  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Model shows main effects, but no interactions important (or at least, detected)

Could you fit a simpler model to the data?

Run simpler model

Permutation test for adonis under reduced model
Terms added sequentially (first to last)
Permutation: free
Number of permutations: 999

adonis2(formula = df1s.bc ~ HIV + candida + gender + smoking_current, data = df, permutations = 999)
                 Df SumOfSqs      R2      F Pr(>F)    
HIV               1    1.369 0.01250 4.3775  0.001 ***
candida           1    1.461 0.01333 4.6693  0.001 ***
gender            1    0.492 0.00449 1.5736  0.009 ** 
smoking_current   1    1.111 0.01014 3.5512  0.001 ***
Residual        336  105.108 0.95953                  
Total           340  109.541 1.00000                  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

No change; not too surprising, as all four main effects were detected easily.

Now go to data visualization

Run 0 stress 0.1573956 
Run 1 stress 0.1575191 
... Procrustes: rmse 0.008589029  max resid 0.09901144 
Run 2 stress 0.1578788 
... Procrustes: rmse 0.01041235  max resid 0.1078867 
Run 3 stress 0.157925 
Run 4 stress 0.1575481 
... Procrustes: rmse 0.01188138  max resid 0.1520687 
Run 5 stress 0.1579133 
Run 6 stress 0.1576591 
... Procrustes: rmse 0.009942152  max resid 0.1527314 
Run 7 stress 0.157497 
... Procrustes: rmse 0.01111373  max resid 0.1522922 
Run 8 stress 0.1579538 
Run 9 stress 0.1576133 
... Procrustes: rmse 0.01189532  max resid 0.1519556 
Run 10 stress 0.1577343 
... Procrustes: rmse 0.005452067  max resid 0.07804308 
Run 11 stress 0.1578963 
Run 12 stress 0.1579279 
Run 13 stress 0.1576016 
... Procrustes: rmse 0.0109762  max resid 0.107016 
Run 14 stress 0.1579049 
Run 15 stress 0.1589585 
Run 16 stress 0.1578044 
... Procrustes: rmse 0.01067844  max resid 0.1064934 
Run 17 stress 0.1579047 
Run 18 stress 0.158098 
Run 19 stress 0.1572868 
... New best solution
... Procrustes: rmse 0.008393785  max resid 0.1530693 
Run 20 stress 0.1575303 
... Procrustes: rmse 0.007358023  max resid 0.09985515 
Run 21 stress 0.1590169 
Run 22 stress 0.1574836 
... Procrustes: rmse 0.007062616  max resid 0.09973642 
Run 23 stress 0.1589497 
Run 24 stress 0.1575418 
... Procrustes: rmse 0.01043605  max resid 0.1071247 
Run 25 stress 0.1575948 
... Procrustes: rmse 0.007994064  max resid 0.100641 
Run 26 stress 0.1589119 
Run 27 stress 0.157732 
... Procrustes: rmse 0.01101245  max resid 0.1526594 
Run 28 stress 0.157637 
... Procrustes: rmse 0.009312799  max resid 0.1014359 
Run 29 stress 0.1578533 
Run 30 stress 0.1580676 
Run 31 stress 0.1576151 
... Procrustes: rmse 0.009459453  max resid 0.152878 
Run 32 stress 0.1577917 
Run 33 stress 0.157414 
... Procrustes: rmse 0.006382718  max resid 0.09822517 
Run 34 stress 0.1576762 
... Procrustes: rmse 0.01303633  max resid 0.1519725 
Run 35 stress 0.158515 
Run 36 stress 0.1591759 
Run 37 stress 0.1581336 
Run 38 stress 0.1576021 
... Procrustes: rmse 0.004976543  max resid 0.08068629 
Run 39 stress 0.157918 
Run 40 stress 0.1579179 
Run 41 stress 0.1579341 
Run 42 stress 0.1582696 
Run 43 stress 0.157666 
... Procrustes: rmse 0.00894034  max resid 0.1018467 
Run 44 stress 0.157331 
... Procrustes: rmse 0.005409824  max resid 0.09767552 
Run 45 stress 0.1577833 
... Procrustes: rmse 0.006683058  max resid 0.08363389 
Run 46 stress 0.1575939 
... Procrustes: rmse 0.008116432  max resid 0.1084878 
Run 47 stress 0.1575258 
... Procrustes: rmse 0.01301618  max resid 0.1519787 
Run 48 stress 0.1592999 
Run 49 stress 0.1579052 
Run 50 stress 0.1576273 
... Procrustes: rmse 0.01129313  max resid 0.1523282 
Run 51 stress 0.1578542 
Run 52 stress 0.1586214 
Run 53 stress 0.1581151 
Run 54 stress 0.1575617 
... Procrustes: rmse 0.004502256  max resid 0.07990366 
Run 55 stress 0.158704 
Run 56 stress 0.1580142 
Run 57 stress 0.1579508 
Run 58 stress 0.1572867 
... New best solution
... Procrustes: rmse 0.0001807269  max resid 0.002841007 
... Similar to previous best
*** Best solution repeated 1 times


Call:
metaMDS(comm = df1s.bc, k = 3, try = 40, trymax = 80, autotransform = FALSE,      maxit = 200) 

global Multidimensional Scaling using monoMDS

Data:     df1s.bc 
Distance: bray 

Dimensions: 3 
Stress:     0.1572867 
Stress type 1, weak ties
Best solution was repeated 1 time in 58 tries
The best solution was from try 58 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: scores missing

Run 0 stress 0.2249552 
Run 1 stress 0.2254015 
... Procrustes: rmse 0.01352051  max resid 0.2271372 
Run 2 stress 0.2255455 
Run 3 stress 0.2258301 
Run 4 stress 0.2253491 
... Procrustes: rmse 0.01645725  max resid 0.2296993 
Run 5 stress 0.22481 
... New best solution
... Procrustes: rmse 0.006257423  max resid 0.08115346 
Run 6 stress 0.226546 
Run 7 stress 0.2270536 
Run 8 stress 0.2255036 
Run 9 stress 0.2253569 
Run 10 stress 0.2248483 
... Procrustes: rmse 0.004470422  max resid 0.08182654 
Run 11 stress 0.2471961 
Run 12 stress 0.2258085 
Run 13 stress 0.2323029 
Run 14 stress 0.2248951 
... Procrustes: rmse 0.004402054  max resid 0.08037907 
Run 15 stress 0.2251572 
... Procrustes: rmse 0.01045667  max resid 0.1510096 
Run 16 stress 0.2253558 
Run 17 stress 0.2254108 
Run 18 stress 0.2250959 
... Procrustes: rmse 0.009892968  max resid 0.1562671 
Run 19 stress 0.225423 
Run 20 stress 0.2248147 
... Procrustes: rmse 0.0005021359  max resid 0.007253184 
... Similar to previous best
Run 21 stress 0.2253845 
Run 22 stress 0.224894 
... Procrustes: rmse 0.004397181  max resid 0.08032982 
Run 23 stress 0.2255606 
Run 24 stress 0.2260425 
Run 25 stress 0.2261645 
Run 26 stress 0.2253466 
Run 27 stress 0.2277116 
Run 28 stress 0.2255894 
Run 29 stress 0.2250862 
... Procrustes: rmse 0.009777865  max resid 0.1540782 
Run 30 stress 0.2257552 
Run 31 stress 0.2253727 
Run 32 stress 0.225797 
Run 33 stress 0.2248478 
... Procrustes: rmse 0.004466226  max resid 0.08183205 
Run 34 stress 0.2250846 
... Procrustes: rmse 0.009723839  max resid 0.1530552 
Run 35 stress 0.2258302 
Run 36 stress 0.2257291 
Run 37 stress 0.22485 
... Procrustes: rmse 0.004479105  max resid 0.08182191 
Run 38 stress 0.2255518 
Run 39 stress 0.2253414 
Run 40 stress 0.2256079 
*** Best solution repeated 1 times


Call:
metaMDS(comm = df1s.bc, k = 2, try = 40, trymax = 80, autotransform = FALSE,      maxit = 200) 

global Multidimensional Scaling using monoMDS

Data:     df1s.bc 
Distance: bray 

Dimensions: 2 
Stress:     0.22481 
Stress type 1, weak ties
Best solution was repeated 1 time in 40 tries
The best solution was from try 5 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: scores missing

3D model fits better than 2D. Stress for 2D above 0.2

Start with plots where symbol colour indicates levels of one of the factors

Try some visualizations of pairs of factors using MDS1 & MDS2 (while 3D is preferred, stress of 3D is around .15, vs 0.22, so not huge difference) Separate HIV+/-, then use symbol colour to separate second factor.

References

Dixon, Kelly M., Geoffrey J. Cary, Graeme L. Worboys, and Philip Gibbons. 2018. “The Disproportionate Importance of Long‐unburned Forests and Woodlands for Reptiles.” Ecology and Evolution 8 (22): 10952–63. https://doi.org/gfs587.
Griffen, Ann L., Zachary A. Thompson, Clifford J. Beall, Elizabeth A. Lilly, Carolina Granada, Kelly D. Treas, Kenneth R. DuBois, et al. 2019. “Significant Effect of HIV/HAART on Oral Microbiota Using Multivariate Analysis.” Scientific Reports 9 (1): 19946. https://doi.org/gsfpz3.
Hutto, David, and Kyle Barrett. 2021. “Do Urban Open Spaces Provide Refugia for Frogs in Urban Environments?” Plos One 16 (1). https://doi.org/gr2r9n.
LS0tCnRpdGxlOiAiQ2ggMTYgZXhlcmNpc2VzIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0aGVtZTogZmxhdGx5CmJpYmxpb2dyYXBoeTogLi4vd2ViX2V4LmJpYgotLS0KCmBgYHtyIGVjaG89RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQojIFBhY2thZ2VzOiB2ZWdhbixtdmFidW5kCnNvdXJjZSgiLi4vUi9saWJyYXJpZXMuUiIpCnNvdXJjZSgiLi4vUi9hcHBlYXJhbmNlLlIiKQpsaWJyYXJ5KHZlZ2FuKQpsaWJyYXJ5KG12YWJ1bmQpCmBgYAoKVGhlIGFpbSBvZiB0aGVzZSBleGVyY2lzZXMgaXMgdG8gY29udGludWUgbWFraW5nIHN1cmUgeW91J3JlIGNvbWZvcnRhYmxlIHdpdGggaGFuZGxpbmcgbXVsdGl2YXJpYXRlIGRhdGEuIEluIHRoaXMgY2hhcHRlcidzLCB5b3UnbGwgZm9jdXMgb24gYW5hbHlzZXMgYmFzZWQgb24gZGlzc2ltaWxhcml0aWVzL2Rpc3RhbmNlcywgaW5jbHVkaW5nIGZpdHRpbmcgbGluZWFyIG1vZGVscyB0byB0aGVzZSBraW5kcyBvZiByZXNwb25zZSB2YXJpYWJsZXMuCgpGb3IgZWFjaCBvZiB0aGUgZXhhbXBsZXMgYmVsb3csIHlvdSBzaG91bGQgZm9sbG93IHRoZSBzZXF1ZW5jZSB3ZSd2ZSB1c2VkIHByZXZpb3VzbHksIGFzIGZhciBhcyBpdCdzIHNlbnNpYmxlOgoKMS4gIFdoYXQgaXMgdGhlIGJpb2xvZ2ljYWwgcXVlc3Rpb24/CgoyLiAgSXMgdGhlIHByZWRpY3RvciBjb250aW51b3VzIG9yIGNhdGVnb3JpY2FsPwoKMy4gIFdyaXRlIG91dCB0aGUgbGluZWFyIG1vZGVsIGNvcnJlc3BvbmRpbmcgdG8gdGhpcyBxdWVzdGlvbi4KCjQuICBXaGF0IGRpc3RyaWJ1dGlvbiBkbyB5b3UgZXhwZWN0IHRoZSByZXNwb25zZSB2YXJpYWJsZSB0byBmb2xsb3c/Cgo1LiAgV2hhdCBhcmUgdGhlIGFzc3VtcHRpb25zIGJlaGluZCB0aGUgc3RhdGlzdGljYWwgbW9kZWwgeW91J2xsIGZpdD8KCiAgICAxLiAgQXJlIHRob3NlIGFzc3VtcHRpb25zIHNhdGlzZmllZD8KCjYuICBGaXQgdGhlIG1vZGVsCgogICAgMS4gIEhvdyB3aWxsIHlvdSBhc3Nlc3Mgd2hldGhlciB0aGUgbW9kZWwgZml0cyB3ZWxsPwoKICAgIDIuICBDYW4geW91IGRldGVjdCBhbiBlZmZlY3Qgb2YgdGhlIHByZWRpY3RvcnM/CgogICAgMy4gIEhvdyBkbyB5b3UgbWVhc3VyZSB0aGUgZWZmZWN0PwoKNy4gIFdoYXQgZG8geW91IGNvbmNsdWRlIChpbmNsdWRpbmcgYW55IGNhdXRpb25zKQoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyBBCgpAZGl4b25EaXNwcm9wb3J0aW9uYXRlSW1wb3J0YW5jZUxvbmcyMDE4IGZvY3VzZWQgb24gYXNzZW1ibGFnZXMgb2YgcmVwdGlsZXMgaW4gZm9yZXN0cyBhbmQgd29vZGxhbmRzIG9mIHNvdXRoZWFzdGVybiBBdXN0cmFsaWEsIHdpdGggYSBwYXJ0aWN1bGFyIGludGVyZXN0IGluIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB0aGVzZSBhc3NlbWJsYWdlcyBhbmQgdGhlIGZpcmUgaGlzdG9yeSBvZiB0aGUgbGFuZHNjYXBlLiBUaGV5IGlkZW50aWZpZWQgODEgc2l0ZXMgdGhhdCB2YXJpZWQgaW4gdGltZSBzaW5jZSBmaXJlLCBmcm9tIDYgbW9udGhzIHRvIFw+OTYgeS4gUmF0aGVyIHRoYW4gYSBjb250aW51dW0sIHRocmVlIGNhdGVnb3JpZXMgb2YgdGltZSBzaW5jZSBmaXJlIHdlcmUgdXNlZCwgMC41LTJ5LCA2LTEyeSwgYW5kIFw+OTZ5LiBTaXRlcyB3ZXJlIGFsc28gY2xhc3NpZmllZCBhY2NvcmRpbmcgdG8gaGFiaXRhdC4KClJlcHRpbGUgYXNzZW1ibGFnZXMgd2VyZSBzYW1wbGVkIHdpdGggYSByYW5nZSBvZiBtZXRob2RzLCBpbmNsdWRpbmcgdmlzdWFsIHN1cnZleXMgYW5kIGNhbWVyYSB0cmFwcywgdG8gZ2l2ZSBjb3VudHMgb2YgMjAgcmVwdGlsZXMsIHdob3NlIGFidW5kYW5jZSByYW5nZWQgZnJvbSAwLTEgdG8gMC0xMjYsIGRlcGVuZGluZyBvbiBzcGVjaWVzLgoKRGF0YSBhcmUgYXZhaWxhYmxlIGZyb20gW2RyeWFkXShodHRwczovL2RhdGFkcnlhZC5vcmcvc3Rhc2gvZGF0YXNldC9kb2k6MTAuNTA2MS9kcnlhZC5naDVtNDcxKSwgYXMgUmVwX2FidW5kLmNzdi4gWW91J2xsIHdhbnQgdG8gZm9jdXMgb24gdGhlIGNvbHVtbnMgd2l0aCByZXB0aWxlIG51bWJlcnMsIGFuZCB0aGUgb25lIHdpdGggdGhlIGZpcmUgaGlzdG9yeSAodHNmKS4gRm9yIGNvbnZlbmllbmNlLCB3ZSd2ZSBleHRyYWN0ZWQgdGhvc2UgZGF0YSBhcyBkaXhvbmJpb3RhLmNzdgoKKipTdGFydCBieSBoYXZpbmcgYSBxdWljayBsb29rIGF0IHRoZSBkYXRhLioqCgpgYGB7cn0KZGYgPC0gcmVhZF9jc3YoIi4uL2RhdGEvZGl4b25iaW90YS5jc3YiKQpoZWFkKGRmLCAxMCkKYGBgCgpUaGUgZmlsZSBpcyBwcmV0dHkgc3RyYWlnaHRmb3J3YXJkLCB3aXRoIHRzZiBiZWluZyB0aGUgZmlyZSBjYXRlZ29yeSwgYW5kIGNvbHVtbnMgMy0yMiBlYWNoIHJlcHJlc2VudGluZyBvbmUgcmVwdGlsZSB0YXhvbi4KCiMjIE91dGxpbmUgaG93IHlvdSdkIGFzc2VzcyB3aGV0aGVyIHRoZSByZXB0aWxlIGFzc2VtYmxhZ2UgKHRoZSBjb21iaW5hdGlvbiBvZiBzcGVjaWVzIHByZXNlbnQgYW5kIHRoZWlyIGFidW5kYW5jZXMpIGlzIHJlbGF0ZWQgdG8gZmlyZSBoaXN0b3J5LCB1c2luZyBhIGRpc3NpbWlsYXJpdHktYmFzZWQgYXBwcm9hY2guCgpZb3Ugc2hvdWxkIHRoaW5rIGFib3V0IGhvdyB5b3UnbGwgZGVhbCB3aXRoIHRoZSBkYXRhOgoKLSAgIFdpbGwgeW91IG5lZWQgYSB0cmFuc2Zvcm1hdGlvbiwgc3RhbmRhcmRpemF0aW9uLCBldGMuPwoKLSAgIFdoYXQgYXJlIHRoZSBjb25zZXF1ZW5jZXMgb2YgYW55IGRlY2lzaW9ucyB5b3UgbWFrZSBmb3IgdGhlIGludGVycHJldGF0aW9uIG9mIHlvdXIgYW5hbHlzaXM/CgotICAgV2hhdCBtZWFzdXJlKHMpIG9mIGRpc3NpbWlsYXJpdHkgYXJlIGFwcHJvcHJpYXRlPwoKIyMjIFJ1biB0aGUgYW5hbHlzaXMgYW5kIHByb3ZpZGUgeW91ciBpbnRlcnByZXRhdGlvbgoKPiAjIyMgTURTIG9uIHJlcHRpbGUgYWJ1bmRhbmNlcwoKPiBTdGFydCB3aXRoIGRpc3NpbWlsYXJpdGllcwo+Cj4gU3R1ZGVudHMgc2hvdWxkIGhhdmUgc29tZSBkaXNjdXNzaW9uIG9mIHJhdyB2cyB0cmFuc2Zvcm1lZCAoZS5nLiA0dGggcm9vdCksIHN0YW5kYXJkaXphdGlvbi4KPgo+IEZvdXJ0aCByb290IGlzIGNvbW1vbi4gVXNpbmcgaXQgZG93bndlaWdodHMgdGhlIGluZmx1ZW5jZSBvZiBhYnVuZGFudCBzcGVjaWVzLCB3aGlsZSByYXcgYWxsb3dzIHRob3NlIHNwZWNpZXMgdG8gaGF2ZSBhIHN0cm9uZyBpbmZsdWVuY2UuIFRoZXJlIGFyZSBxdWVzdGlvbnMgYWJvdXQgd2hpY2ggb25lIG9mIHRoZXNlIHJlZmxlY3RzIGVjb2xvZ2ljYWwgZnVuY3Rpb24gYmV0dGVyCj4KPiBEYXRhIGFyZSBhbGwgYWJ1bmRhbmNlcwoKYGBge3J9CmRmMSA8LSBkZlssLSgxOjIpXSAgICNTdHJpcHBlZCBiYWNrIGZpbGUgd2l0aG91dCBsYWJlbHMsIGxlYXZpbmcgb25seSAKZGYxcyA8LSB3aXNjb25zaW4oZGYxKSAgICNDb21tb24gdG8gZG8gc29tZSBzdGFuZGFyZGlzYXRpb24KZGYxcy5iYyA8LSB2ZWdkaXN0KGRmMXMsJ2JyYXknKSAgICNXaXRoIHN0YW5kYXJkaXNhdGlvbiAod2lzY29uc2luKQpgYGAKCj4gVmlzdWFsaXplIHJlc3VsdHMKCj4gTmVlZCB0byBkZWNpZGUgd2hldGhlciB0byB1c2UgMiBvciAzIGRpbWVuc2lvbnMKCmBgYHtyfQojUnVuIDNkIGZpcnN0CmRmMXMubWRzMyA8LSBtZXRhTURTKGRmMXMuYmMsaz0zLGF1dG90cmFuc2Zvcm09RkFMU0UsdHJ5PTQwLHRyeW1heD04MCxtYXhpdD0yMDApCnN0cmVzc3Bsb3QoZGYxcy5tZHMzLCBtYWluPSJTaGVwYXJkIHBsb3QiKQpkZjFzLm1kczMKIyBOb3cgbG9vayBhdCAyZApkZjFzLm1kczIgPC0gbWV0YU1EUyhkZjFzLmJjLGs9MixhdXRvdHJhbnNmb3JtPUZBTFNFLHRyeT00MCx0cnltYXg9ODAsbWF4aXQ9MjAwKQpzdHJlc3NwbG90KGRmMXMubWRzMiwgbWFpbj0iU2hlcGFyZCBwbG90IikKZGYxcy5tZHMyCmBgYAoKPiBTdHJlc3MgdmFsdWVzIHN1Z2dlc3QgM2QgcGxvdCBpcyBhIG1vcmUgYWNjdXJhdGUgcmVwcmVzZW50YXRpb24KCj4gTmVlZCB0byBwbG90IGRpbSAxIHZzIGRpbSAyIGFuZCBkaW0gMSB2cyBkaW0gMyB3aXRoIHRzZiBncm91cHMgaWRlbnRpZmllZCBieSBzeW1ib2xzCj4KPiAqKkdlbmVyYXRlIGdyYXBocyoqCj4KPiBUaGlzIGlzIGEgdmFyaWFudCBvZiBjb2RlIHVzZWQgaW4gd29ya2VkIGV4YW1wbGUgZm9yIENoIDE2LiBJdCBkb2VzIHVzZSB0aGUgZ3JhcGggc2V0dGluZ3MgZGVmaW5lZCBpbiAqYXBwZWFyYW5jZS5SKiwgd2hpY2ggaXMgY2FsbGVkIGVhcmxpZXIuCgpgYGB7cn0KYTwtYXMuZGF0YS5mcmFtZShzY29yZXMoZGYxcy5tZHMzKSkKYTwtY2JpbmQoZGZbYygxOjIpXSxhKSAgICNBZGQgc2l0ZSBuYW1lcyAmIHN5bWJvbHMgZnJvbSBvcmlnaW5hbCBkYXRhIGZpbGUKcDE8LWdncGxvdChkYXRhPWEsIGFlcyh4PU5NRFMxLCB5PU5NRFMyLCBjb2xvcj10c2YsICkgKSsKICBnZW9tX3BvaW50KCkrCiAgbGFicyh5PSJNRFMyIiwgeD0iTURTMSIpKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9c3ltMywKICAgICAgICAgICAgICAgICAgICAgbmFtZT0iVFNGIiwKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPQogICAgICAgICAgICAgICAgICAgICAgICAgZ3VpZGVfbGVnZW5kKGxhYmVsLnRoZW1lID0gZWxlbWVudF90ZXh0KHNpemU9NiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlPU5VTEwpCiAgICAgICAgICAgICAgICAgICAgICkKcDI8LWdncGxvdChkYXRhPWEsIGFlcyh4PU5NRFMxLCB5PU5NRFMzLCBjb2xvciA9IHRzZiwgKSApKwogIGdlb21fcG9pbnQoKSsKICBsYWJzKHk9Ik1EUzMiLCB4PSJNRFMxIikrCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcz1zeW0zLAogICAgICAgICAgICAgICAgICAgICBuYW1lPSJUU0YiLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9CiAgICAgICAgICAgICAgICAgICAgICAgICBndWlkZV9sZWdlbmQobGFiZWwudGhlbWUgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGU9TlVMTCkKICAgICAgICAgICAgICAgICAgICAgKQoKcDEgKyBwMiArIHBsb3RfbGF5b3V0KGd1aWRlcz0nY29sbGVjdCcpICYgdGhlbWVfcWsoKSAmIHNjYWxlX2NvbG9yX3VjaGljYWdvKCkKYGBgCgojIyMgSG93IHdvdWxkIHlvdSBmaXQgYSBsaW5lYXIgbW9kZWwgdG8gYXNzZXNzIGZpcmUgZWZmZWN0cz8KCj4gRG8gcGVybWFub3ZhIGluY2x1ZGluZyB0c2YKCmBgYHtyfQpkZjFzLmFkbyA8LSBhZG9uaXMyKGRmMXMuYmN+dHNmLGRhdGE9ZGYscGVybXV0YXRpb25zPTk5OSkKcHJpbnQoZGYxcy5hZG8pCmBgYAoKPiBQZXJtYW5vdmEgc3VnZ2VzdHMgc3Ryb25nIHNpZ25hbCBmcm9tIHRzZgoKPiBTSU1QRVIgYW5hbHlzaXMgZm9yIHRzZiBncm91cCBkaWZmZXJlbmNlcwoKYGBge3J9CmRmLnNpbSA8LSBzaW1wZXIoZGYxc1ssLSgxOjIpXSwgZGYkdHNmLCBwZXJtdXRhdGlvbnM9MTAwMCkKc3VtbWFyeShkZi5zaW0pCmBgYAoKIyMgU3VwcG9zZSB5b3UgdGhpbmsgb2YgYSByZXB0aWxlIGFzc2VtYmxhZ2UgYXMgc2ltcGx5IHRoZSBzcGVjaWVzIHRoYXQgYXJlIHByZXNlbnQsIHJlZ2FyZGxlc3Mgb2YgaG93IGNvbW1vbiB0aGV5IGFyZS4gV2hhdCB3b3VsZCB5b3UgY29uY2x1ZGUgYWJvdXQgdGhlIGluZnVlbmNlIG9mIHRpbWUgc2luY2UgZmlyZSBub3c/Cgo+IFJlcGVhdCB0aGUgcHJlY2VkaW5nIGFuYWx5c2lzIGFmdGVyIGNyZWF0aW5nIGEgbmV3IGRhdGEgZmlsZSB0aGF0IGlzIHByZXNlbmNlLWFic2VuY2Ugb25seS4KCmBgYHtyfQpkZjEuamFjIDwtIHZlZ2Rpc3QoZGYxLGJpbmFyeT1UUlVFLG1ldGhvZD0namFjY2FyZCcpCiNSdW4gM2QgZmlyc3QKZGYxcy5tZHMzIDwtIG1ldGFNRFMoZGYxLmphYyxrPTMsYXV0b3RyYW5zZm9ybT1GQUxTRSx0cnk9NDAsdHJ5bWF4PTgwLG1heGl0PTIwMCkKc3RyZXNzcGxvdChkZjFzLm1kczMsIG1haW49IlNoZXBhcmQgcGxvdCIpCmRmMXMubWRzMwojIE5vdyBsb29rIGF0IDJkCmRmMXMubWRzMiA8LSBtZXRhTURTKGRmMS5qYWMsaz0yLGF1dG90cmFuc2Zvcm09RkFMU0UsdHJ5PTQwLHRyeW1heD04MCxtYXhpdD0yMDApCnN0cmVzc3Bsb3QoZGYxcy5tZHMyLCBtYWluPSJTaGVwYXJkIHBsb3QiKQpkZjFzLm1kczIKYGBgCgo+IE1hcmdpbmFsIGRlY2lzaW9uIGhlcmUgLSBzdHJlc3MganVzdCBvdmVyIDAuMiBmb3Igaz0yLCBzbyBtaWdodCBiZSBPSy4gU3RyZXNzIGdvb2QgZm9yIGs9MywgYnV0IDItZCBNRFMgdXN1YWxseSBiZXR0ZXIgZm9yIHJlcG9ydGluZyBvciBzaG93aW5nIHRvIGF1ZGllbmNlCgpgYGB7cn0KYTwtYXMuZGF0YS5mcmFtZShzY29yZXMoZGYxcy5tZHMzKSkKYTwtY2JpbmQoZGZbYygxOjIpXSxhKSAgICNBZGQgc2l0ZSBuYW1lcyAmIHN5bWJvbHMgZnJvbSBvcmlnaW5hbCBkYXRhIGZpbGUKcDE8LWdncGxvdChkYXRhPWEsIGFlcyh4PU5NRFMxLCB5PU5NRFMyLCBjb2xvcj10c2YsICkgKSsKICBnZW9tX3BvaW50KCkrCiAgbGFicyh5PSJNRFMyIiwgeD0iTURTMSIpKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9c3ltMywKICAgICAgICAgICAgICAgICAgICAgbmFtZT0iVFNGIiwKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPQogICAgICAgICAgICAgICAgICAgICAgICAgZ3VpZGVfbGVnZW5kKGxhYmVsLnRoZW1lID0gZWxlbWVudF90ZXh0KHNpemU9NiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlPU5VTEwpCiAgICAgICAgICAgICAgICAgICAgICkKcDI8LWdncGxvdChkYXRhPWEsIGFlcyh4PU5NRFMxLCB5PU5NRFMzLCBjb2xvciA9IHRzZiwgKSApKwogIGdlb21fcG9pbnQoKSsKICBsYWJzKHk9Ik1EUzMiLCB4PSJNRFMxIikrCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcz1zeW0zLAogICAgICAgICAgICAgICAgICAgICBuYW1lPSJUU0YiLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9CiAgICAgICAgICAgICAgICAgICAgICAgICBndWlkZV9sZWdlbmQobGFiZWwudGhlbWUgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGU9TlVMTCkKICAgICAgICAgICAgICAgICAgICAgKQoKcDEgKyBwMiArIHBsb3RfbGF5b3V0KGd1aWRlcz0nY29sbGVjdCcpICYgdGhlbWVfcWsoKSAmIHNjYWxlX2NvbG9yX3VjaGljYWdvKCkKYGBgCgo+IFVuYnVybmVkIHNpdGVzIHNlcGFyYXRlIHZlcnkgY2xlYXJseSBvbiBNRFMxLiBQYXR0ZXJuIGNsZWFyZXIgdGhhbiB3aXRoIGFidW5kYW5jZXMgaW5jbHVkZWQKCj4gRG8gcGVybWFub3ZhIGluY2x1ZGluZyB0c2YKCmBgYHtyfQpkZjEuYWRvIDwtIGFkb25pczIoZGYxLmphY350c2YsZGF0YT1kZixwZXJtdXRhdGlvbnM9OTk5KQpwcmludChkZjEuYWRvKQpgYGAKCj4gQ2xlYXIgZmlyZSBzaWduYWwKCiMjIEV4dGVuc2lvbiBhY3Rpdml0eQoKRGl4b24gYW5kIGhlciBjb2xsZWFndWVzIGFsc28gcmVjb3JkZWQgYSByYW5nZSBvZiBoYWJpdGF0IHZhcmlhYmxlcywgd2hpY2ggd2UndmUgY29sbGVjdGVkIGZvciB5b3UgaW4gZGl4b25lbnYuY3N2CgpgYGB7cn0KZGl4b25lbnYgPC0gcmVhZF9jc3YoIi4uL2RhdGEvZGl4b25lbnYuY3N2IikKaGVhZChkaXhvbmVudiwgMTApCmBgYAoKVGhleSByZWNvcmRlZCBDb2Fyc2UgV29vZHkgRGVicmlzLCB3aGljaCB3YXMgbG9uZy10cmFuc2Zvcm1lZCwgbGl0dGVyIGNvdmVyIChsaXRjb3YpLCAlIGNvdmVyIG9mIGdyb3VuZGNvdmVyIChncmNvdiksIGFuZCAlIGNvdmVyIG9mIHNocnVicyAoc2hyY292KSwgYW5kIHJvY2sgY292ZXIuIEluIHRoZSBvcmlnaW5hbCBwYXBlciwgRGl4b24gZXQgYWwuIHdlcmUgY29tZm9ydGFibGUgdGhhdCB0aGVzZSBwcmVkaWN0b3JzIHdlcmVuJ3QgY29ycmVsYXRlZC4KCiMjIyBIb3cgaXMgcmVwdGlsZSBhc3NlbWJsYWdlIHJlbGF0ZWQgdG8gdGltZSBzaW5jZSBmaXJlIGFuZCB0aGVzZSBmaXZlIGhhYml0YXQgdmFyaWFibGVzCgo+IENoZWNrIGNvbnRpbnVvdXMgcHJlZGljdG9ycwoKYGBge3J9CmJveHBsb3QoZGl4b25lbnYkbGN3ZCkKYm94cGxvdChkaXhvbmVudiRsaXRjb3YpCmJveHBsb3QoZGl4b25lbnYkZ3Jjb3YpCmJveHBsb3QoZGl4b25lbnYkc2hyY292KQpib3hwbG90KGRpeG9uZW52JHJvY2tzKQojdHJhbnNmb3JtIHJvY2tzIHRvIGxvZysxCmRpeG9uZW52JGxyb2NrcyA8LSBsb2cxMChkaXhvbmVudiRyb2NrcysxKQojIGNoZWNrIGhvbW9nIG9mIGRpc3BlcnNpb25zIG9uIGRvdWJsZSBzdGFuZGFyZGl6ZWQgYWJ1bmRhbmNlcwpkZjFzLmRpc3AgPC0gYmV0YWRpc3BlcihkZjFzLmJjLGRmJHRzZikKYW5vdmEoZGYxcy5kaXNwKQpgYGAKCj4gZG8gcGVybWFub3ZhIGluY2x1ZGluZyB0c2YgcGx1cyBjb250aW51b3VzIHByZWRpY3RvcnMKCmBgYHtyfQpkZjFzLmFkbyA8LSBhZG9uaXMyKGRmMXMuYmN+dHNmK2xjd2QrbGl0Y292K2dyY292K3NocmNvditscm9ja3MsZGF0YT1kaXhvbmVudixwZXJtdXRhdGlvbnM9OTk5KQpwcmludChkZjFzLmFkbykKI1J1biBhbmFseXNpcyBmb3IgcHJlc2VuY2UtYWJzZW5jZSBhcyB3ZWxsCmRmMS5qYWMuYWRvIDwtIGFkb25pczIoZGYxLmphY350c2YrbGN3ZCtsaXRjb3YrZ3Jjb3Yrc2hyY292K2xyb2NrcyxkYXRhPWRpeG9uZW52LHBlcm11dGF0aW9ucz05OTkpCnByaW50KGRmMS5qYWMuYWRvKQoKYGBgCgo+IE1haW4gZWZmZWN0IGlzIHRzZjsgb25seSBzb21lIHF1ZXN0aW9uIGFib3V0IENXRCB3aGVuIHdlIGxvb2sgYXQgc3BlY2llcyBjb21wb3NpdGlvbiBhbmQgYWJ1bmRhbmNlLCB3aGlsZSBmb3IgcHJlc2VuY2UtYWJzZW5jZSBkYXRhLCB0aGVyZSBhcmUgYWxzbyBlZmZlY3RzIG9mIENXRCBhbmQgZ3JvdW5kY292ZXIKCiMjIyBtdmFidW5kCgpgYGB7ciBlcnJvcj1UUlVFfQpkZm12IDwtIG12YWJ1bmQoZGZbLC0oMToyKV0pCmRmbXYubXYgPC0gbWFueWdsbShkZm12fmRpeG9uZW52JHRzZitkaXhvbmVudiRsY3dkK2RpeG9uZW52JGxpdGNvditkaXhvbmVudiRncmNvditkaXhvbmVudiRzaHJjb3YrZGl4b25lbnYkbHJvY2tzLGZhbWlseT0icG9pc3NvbiIpCnBsb3QoZGl4b25iaW90YW12Lm12KQojIHN0aWxsIGhldGVybyB2YXJzIHNvIHVzZSAtdmUgYmlub21pYWwKZGZtdjEubXYgPC0gbWFueWdsbShkZm12fmRpeG9uZW52JHRzZitkaXhvbmVudiRsY3dkK2RpeG9uZW52JGxpdGNvditkaXhvbmVudiRncmNvditkaXhvbmVudiRzaHJjb3YrZGl4b25lbnYkbHJvY2tzLGZhbWlseT0ibmVnYXRpdmVfYmlub21pYWwiKQpwbG90KGRmbXYxLm12KQphbm92YShkZm12MS5tdikKYGBgCgojIyBCIFNpbXBsZSBNRFMgJiBQZXJtYW5vdmEKCkxldCdzIHJldHVybiB0byB0aGUgQGh1dHRvVXJiYW5PcGVuU3BhY2VzMjAyMSBleGFtcGxlIGZyb20gdGhlIENoYXB0ZXIgMTUgZXhlcmNpc2VzLiBUaGVyZSwgd2UgdXNlZCBzaW1pbGFyaXR5LWJhc2VkIGFuYWx5c2VzIHRvIGV4cGxvcmUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGZyb2cgYXNzZW1ibGFnZXMgaW4gcG9uZHMgYW5kIHRoZSBkZWdyZWUgb2YgdXJiYW5pemF0aW9uIHN1cnJvdW5kaW5nLiBUaGlzIHNlZW1zIGEgcXVlc3Rpb24gdGhhdCBjb3VsZCBqdXN0IGFzIGVhc2lseSBiZSBleGFtaW5lZCB1c2luZyBkaXN0YW5jZXMgb3IgZGlzc2ltaWxhcml0aWVzLgoKUmV0dXJuIHRvIHRoZSBkYXRhIGFuZCBhc3Nlc3Mgd2hldGhlciBmcm9nIGFzc2VtYmxhZ2VzICh1c2luZyB0aGUgc3RhbmRhcmRpemVkIGFidW5kYW5jZSBzY2FsZSBvciBwcmVzZW5jZS1hYnNlbmNlKSBkaWZmZXIgd2l0aCB1cmJhbml6YXRpb24uCgojIyMjIERpZCB5b3VyIGNvbmNsdXNpb25zIGRpZmZlciBmcm9tIHRob3NlIG9idGFpbmVkIHVzaW5nIFJEQT8KCmBgYHtyfQpkZiA8LSByZWFkX2NzdigiLi4vZGF0YS9odXR0b2FtcGguY3N2IikKaGVhZChkZiwxMCkKI3BvbmRzIDkgYW5kIDQwIGhhZCBubyBmcm9ncy4gUmVtb3ZlIGZvciBkaXN0YW5jZSBhbmFseXNpcwpkZiA8LSBkZiAlPiUgCiAgZmlsdGVyKFNpdGUhPSA5ICYgU2l0ZSAhPTQwKQpkZgpgYGAKClRoZSBleHBsYW5hdGlvbiBvZiB0aGUgdmFyaWFibGVzIGlzIGluIHRoZSBwcmV2aW91cyBjaGFwdGVyJ3MgZXhlcmNpc2VzLgoKYGBge3J9CmRmMSA8LSBkZlssLSgxOjIpXSAgICNTdHJpcHBlZCBiYWNrIGZpbGUgd2l0aG91dCBsYWJlbHMsIGxlYXZpbmcgb25seSAKZGYxLmJjIDwtIHZlZ2Rpc3QoZGYxLCdicmF5JykKYGBgCgpgYGB7cn0KI1J1biAyZCBmaXJzdApkZjEubWRzMiA8LSBtZXRhTURTKGRmMS5iYyxrPTIsYXV0b3RyYW5zZm9ybT1GQUxTRSx0cnk9NDAsdHJ5bWF4PTgwLG1heGl0PTIwMCkKc3RyZXNzcGxvdChkZjEubWRzMiwgbWFpbj0iU2hlcGFyZCBwbG90IikKZGYxLm1kczIKIyBOb3cgbG9vayBhdCAzZApkZi5tZHMzIDwtIG1ldGFNRFMoZGYxLmJjLGs9MyxhdXRvdHJhbnNmb3JtPUZBTFNFLHRyeT00MCx0cnltYXg9ODAsbWF4aXQ9MjAwKQpzdHJlc3NwbG90KGRmLm1kczMsIG1haW49IlNoZXBhcmQgcGxvdCIpCmRmLm1kczMKYGBgCgo+IDItZCBpcyBhY2NlcHRhYmxlCgpgYGB7cn0KYTwtYXMuZGF0YS5mcmFtZShzY29yZXMoZGYxLm1kczIpKQphPC1jYmluZChkZltjKDE6MildLGEpICAgI0FkZCBzaXRlIG5hbWVzICYgc3ltYm9scyBmcm9tIG9yaWdpbmFsIGRhdGEgZmlsZQpnZ3Bsb3QoZGF0YT1hLCBhZXMoeD1OTURTMSwgeT1OTURTMiwgY29sb3I9dHlwZSwgKSApKwogIGdlb21fcG9pbnQoKSsKICBsYWJzKHk9Ik1EUzIiLCB4PSJNRFMxIikrCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcz1zeW0zLAogICAgICAgICAgICAgICAgICAgICBuYW1lPSJVcmJhbml6YXRpb24iLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9CiAgICAgICAgICAgICAgICAgICAgICAgICBndWlkZV9sZWdlbmQobGFiZWwudGhlbWUgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGU9TlVMTCkKICAgICAgICAgICAgICAgICAgICAgKSsKICB0aGVtZV9xaygpICsgc2NhbGVfY29sb3JfdWNoaWNhZ28oKQpgYGAKCmBgYHtyfQpkZjEuYWRvIDwtIGFkb25pczIoZGYxLmJjfnR5cGUsZGF0YT1kZixwZXJtdXRhdGlvbnM9OTk5KQpwcmludChkZjEuYWRvKQpgYGAKCj4gUGVybWFub3ZhIGRldGVjdHMgYSBkaWZmZXJlbmNlOyBNRFMgcGxvdCBzdWdnZXN0cyBsb3cgdXJiYW5pemF0aW9uIG1heSBiZSBkaWZmZXJlbnQgZnJvbSB0aGUgb3RoZXIgdHdvLCB0aG91Z2ggd29ydGggbG9va2luZyBhdCBkaXNwZXJzaW9uIGFzIHdlbGwsIGFzIHNwcmVhZCBvZiB0aGlzIHR5cGUgaXMgbGVzcyB0aGFuIHRoZSBvdGhlciB0d28gb24gcGxvdAoKPiBSZXBlYXQgYW5hbHlzaXMgd2l0aCBwcmVzZW5jZS1hYnNlbmNlCgpkZjEuamFjIFw8LSB2ZWdkaXN0KGRmMSxiaW5hcnk9VFJVRSxtZXRob2Q9J2phY2NhcmQnKQoKYGBge3J9CiNSdW4gMmQgZmlyc3QKZGYxLmphYyA8LSB2ZWdkaXN0KGRmMSxiaW5hcnk9VFJVRSxtZXRob2Q9J2phY2NhcmQnKQpkZjEubWRzMiA8LSBtZXRhTURTKGRmMS5qYWMsaz0yLGF1dG90cmFuc2Zvcm09RkFMU0UsdHJ5PTQwLHRyeW1heD04MCxtYXhpdD0yMDApCnN0cmVzc3Bsb3QoZGYxLm1kczIsIG1haW49IlNoZXBhcmQgcGxvdCIpCmRmMS5tZHMyCiMgTm93IGxvb2sgYXQgM2QKZGYubWRzMyA8LSBtZXRhTURTKGRmMS5qYWMsaz0zLGF1dG90cmFuc2Zvcm09RkFMU0UsdHJ5PTQwLHRyeW1heD04MCxtYXhpdD0yMDApCnN0cmVzc3Bsb3QoZGYubWRzMywgbWFpbj0iU2hlcGFyZCBwbG90IikKZGYubWRzMwpgYGAKCj4gQWdhaW4sIHN0cmVzcyBPSyB3aXRoIDJELCBnb29kIHdpdGggM0QuIExvb2sgYXQgMkQgZmlyc3QKCmBgYHtyfQphPC1hcy5kYXRhLmZyYW1lKHNjb3JlcyhkZjEubWRzMikpCmE8LWNiaW5kKGRmW2MoMToyKV0sYSkgICAjQWRkIHNpdGUgbmFtZXMgJiBzeW1ib2xzIGZyb20gb3JpZ2luYWwgZGF0YSBmaWxlCmdncGxvdChkYXRhPWEsIGFlcyh4PU5NRFMxLCB5PU5NRFMyLCBjb2xvcj10eXBlLCApICkrCiAgZ2VvbV9wb2ludCgpKwogIGxhYnMoeT0iTURTMiIsIHg9Ik1EUzEiKSsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPXN5bTMsCiAgICAgICAgICAgICAgICAgICAgIG5hbWU9IlVyYmFuaXphdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0KICAgICAgICAgICAgICAgICAgICAgICAgIGd1aWRlX2xlZ2VuZChsYWJlbC50aGVtZSA9IGVsZW1lbnRfdGV4dChzaXplPTYpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZT1OVUxMKQogICAgICAgICAgICAgICAgICAgICApKwogIHRoZW1lX3FrKCkgKyBzY2FsZV9jb2xvcl91Y2hpY2FnbygpCmBgYAoKYGBge3J9CmRmMS5hZG8gPC0gYWRvbmlzMihkZjEuamFjfnR5cGUsZGF0YT1kZixwZXJtdXRhdGlvbnM9OTk5KQpwcmludChkZjEuYWRvKQpgYGAKCj4gTm8gc2VwYXJhdGlvbiBzZWVuIG9uIFByZXNlbmNlLUFic2VuY2UKCiMjIEMKCkBncmlmZmVuU2lnbmlmaWNhbnRFZmZlY3RISVYyMDE5IGV4YW1pbmVkIHRoZSBvcmFsIG1pY3JvYmlvbWUgb2YgaHVtYW5zLCB3aXRoIGEgZm9jdXMgb24gdGhlIGVmZmVjdHMgb2YgSElWIGFuZCBBbnRpUmV0cm92aXJhbCB0aGVyYXB5IChBUlQpIG9uIHRoaXMgbWljcm9iaW9tZS4gVGhleSBkZXNjcmliZWQgdGhlIG1pY3JvYmlvbWUgb2YgMzQxIHBhdGllbnRzLCB3aG8gZmVsbCBpbnRvIG9uZSBvZiB0d28gY2F0ZWdvcmllczogSElWXi1eLCBhbmQgSElWKyB3aXRoIEFSVC4gVGhleSBhbHNvIG1hdGNoZWQgdGhlaXIgc2FtcGxlcyBhcyBmYXIgYXMgcG9zc2libGUgZm9yIHNleCwgYWxvbmcgd2l0aCBvdGhlciBjb25kaXRpb25zIHRoYXQgY2FuIGluZmx1ZW5jZSBvcmFsIG1pY3JvYmlvbWVzICgqQ2FuZGlkYSogaW5mZWN0aW9uLCBjdXJyZW50IHNtb2tpbmcpLiBXZSdsbCB1c2UgdGhlaXIgcmVjb3JkcyBmb3IgdGhlc2Ugb3RoZXIgY2F0ZWdvcmllcyBhcyB3ZWxsLiBUaGVyZSB3ZXJlIG1vcmUgSElWKyB0aGFuIC0gc3ViamVjdHMsIGJ1dCB3aXRoaW4gdGhlc2UgZ3JvdXBzLCBhcHByb3hpbWF0ZWx5IGVxdWFsIG51bWJlcnMgb2YgdHdvIHNleGVzLCB0d28gKkNhbmRpZGEqIGluZmVjdGlvbiBzdGF0dXMsIGFuZCB0d28gc21va2luZyBjYXRlZ29yaWVzLgoKVGhlIGJhY3RlcmlvbWUgd2FzIHJlY29yZGVkIHNlcGFyYXRlbHkgdXNpbmcgMTZTIFJOQSBzZXF1ZW5jaW5nLCB3aGljaCBvdmVyZWQganVzdCBvdmVyIDYwMCB0YXhhLgoKVGhlIGRhdGEgYXJlIGF2YWlsYWJsZSBmcm9tIHRoZWlyIHBhcGVyLCBhcyB0d28gRXhjZWwgZmlsZXMgaW4gdGhlIHN1cHBsZW1lbnRhcnkgaW5mb3JtYXRpb24uIFRoZSBtZXRhZGF0YSBnaXZlcyBISVYgc3RhdHVzLCBhbmQgYSByYWZ0IG9mIGRlbW9ncmFwaGljIGluZm9ybWF0aW9uLiBXZSdsbCBqdXN0IHdvcmsgd2l0aCBISVYsIHNleCwgKkNhbmRpZGEqLCBhbmQgY3VycmVudCBzbW9raW5nLiBBIHNlY29uZCBzaGVldCBoYXMgdGhlIGJhY3RlcmlvbWUuIFRoZSBjb2RlIGNodW5rIGJlbG93IHJlYWRzIHRoaXMgZmlsZSAoZnJvbSBhIERvd25sb2FkcyBmb2xkZXIgLSB5b3UnbGwgbmVlZCB0byBtb2RpZnkgdGhlIGZpbGUgbG9jYXRpb24pLiBJdCBhbHNvIHNjcmVlbnMgdGhlIGZpbGUgZm9yIGFueSBiYWN0ZXJpYWwgdGF4YSB0aGF0IHdlcmUgbm90IHByZXNlbnQgaW4gdGhpcyBwYXJ0aWN1bGFyIHN0dWR5LCB3aGljaCByZWR1Y2VzIHRoZSBiYWN0ZXJpYWwgdGF4YSB0byA1OTkuCgpgYGB7ciBkZn0KbGlicmFyeShyZWFkeGwpCiNSZWFkIGluIG1ldGFkYXRhLiBMb3RzIG9mIGluZm9ybWF0aW9uIHdlIGRvbid0IG5lZWQsIHNvIGEgY291cGxlIG9mIGl0ZXJhdGlvbnMgdG8gZ2V0IGRvd24gdG8gYSBmZXcgY29sdW1ucyB3ZSB3YW50IC0gSElWIHN0YXR1cywgY2FuZGlkYSwgY3VycmVudCBzbW9raW5nLCBnZW5kZXIKZGYgPC0gcmVhZF9leGNlbCgiLi4vZGF0YS80MTU5OF8yMDE5XzU1NzAzX01PRVNNM19FU00ueGxzeCIsIAogICAgIHJhbmdlID0gIkExOlMzNDIiLCBuYSA9ICJOQSIpCmRmPC1zZWxlY3QoZGYsIEhJViwgY2FuZGlkYSwgZ2VuZGVyLCBzbW9raW5nX2N1cnJlbnQpCmhlYWQoZGYpCiNkZjEgaXMgdGhlIGJhY3RlcmlhbCBkYXRhCmRmMSA8LSByZWFkX2V4Y2VsKCIuLi9kYXRhLzQxNTk4XzIwMTlfNTU3MDNfTU9FU00yX0VTTS54bHN4IikKaGVhZChkZjEsMTApCmRmMSA8LSBkZjEgJT4lCiAgc2VsZWN0KHdoZXJlKCB+IGlzLm51bWVyaWMoLngpICYmIHN1bSgueCkgIT0gMCkpICAjRHJvcHMgYW55IGJhY3RlcmlhbCB0YXhvbiBub3QgcmVjb3JkZWQgaW4gdGhpcyBzdHVkeSAoaS5lLiB3aGVyZSBpdCdzIGFsbCB6ZXJvZXMpCmRmMSA8LSBkZjFbLC0xXSAjcmVtb3ZlIGNvbDEsIHdoaWNoIGlzIHNhbXBsZSBJRApgYGAKCiMjIyBVc2UgYSBkaXNzaW1pbGFyaXR5IGJhc2VkIGFwcHJvYWNoIHRvIGFzc2VzcyB0aGUgY29tYmluZWQgZWZmZWN0cyBvZiBISVYtQVJULCBzZXgsICpDYW5kaWRhKiBpbmZlY3Rpb24sIGFuZCBjdXJyZW50IHNtb2tpbmcgb24gdGhlIGJhY3RlcmlvbWUKCioqRG8gdGhlc2UgZmFjdG9ycyBhY3QgaW5kZXBlbmRlbnRseSBvbiB0aGUgYmFjdGVyaW9tZT8qKgoKKipXaGljaCBlZmZlY3RzIGFyZSBsYXJnZXN0ICh1c2Ugc29tZSBncmFwaGljYWwgbWV0aG9kcyk/KioKCioqRmlyc3Qgc3RlcHM6KiogVGhpbmsgYWJvdXQgc3RhbmRhcmRpemF0aW9uIGFuZCB3aGljaCBkaXN0YW5jZSBtZWFzdXJlIHlvdSdsbCB1c2UuIEJyYXktQ3VydGlzIHNlZW1zIGNvbW1vbiBmb3IgdGhlc2Uga2luZCBvZiBkYXRhLCBhbmQgYW5kIGNvdW50cyBvZiBkaWZmZXJlbnQgdGF4YSB2YXJ5IHdpZGVseS4KCmBgYHtyIEJDfQpkZjFzIDwtIHdpc2NvbnNpbihkZjEpICAgI0NvbW1vbiB0byBkbyBzb21lIHN0YW5kYXJkaXNhdGlvbiwgYW5kIGNvdW50cyBvZiBkaWZmZXJlbnQgdGF4YSB2YXJ5IHdpZGVseQpkZjFzLmJjIDwtIHZlZ2Rpc3QoZGYxcywnYnJheScpICAgI1dpdGggc3RhbmRhcmRpc2F0aW9uICh3aXNjb25zaW4pCmBgYAoKPlJ1biBmYWN0b3JpYWwgbW9kZWwgdXNpbmcgcGVybWFub3ZhLCBiYXNlZCBvbiBCLUMKCmBgYHtyfQpkZjEuYWRvIDwtIGFkb25pczIoZGYxcy5iY35ISVYqY2FuZGlkYSpnZW5kZXIqc21va2luZ19jdXJyZW50LGRhdGE9ZGYscGVybXV0YXRpb25zPTk5OSkKcHJpbnQoZGYxLmFkbykKYGBgCgo+TW9kZWwgc2hvd3MgbWFpbiBlZmZlY3RzLCBidXQgbm8gaW50ZXJhY3Rpb25zIGltcG9ydGFudCAob3IgYXQgbGVhc3QsIGRldGVjdGVkKQoKKipDb3VsZCB5b3UgZml0IGEgc2ltcGxlciBtb2RlbCB0byB0aGUgZGF0YT8qKgoKPlJ1biBzaW1wbGVyIG1vZGVsCgpgYGB7cn0KZGYyLmFkbyA8LSBhZG9uaXMyKGRmMXMuYmN+SElWK2NhbmRpZGErZ2VuZGVyK3Ntb2tpbmdfY3VycmVudCxkYXRhPWRmLHBlcm11dGF0aW9ucz05OTkpCnByaW50KGRmMi5hZG8pCmBgYAoKPk5vIGNoYW5nZTsgbm90IHRvbyBzdXJwcmlzaW5nLCBhcyBhbGwgZm91ciBtYWluIGVmZmVjdHMgd2VyZSBkZXRlY3RlZCBlYXNpbHkuCgo+Tm93IGdvIHRvIGRhdGEgdmlzdWFsaXphdGlvbgoKYGBge3J9CiNSdW4gM2QgZmlyc3QKZGYxcy5tZHMzIDwtIG1ldGFNRFMoZGYxcy5iYyxrPTMsYXV0b3RyYW5zZm9ybT1GQUxTRSx0cnk9NDAsdHJ5bWF4PTgwLG1heGl0PTIwMCkKc3RyZXNzcGxvdChkZjFzLm1kczMsIG1haW49IlNoZXBhcmQgcGxvdCIpCmRmMXMubWRzMwojIE5vdyBsb29rIGF0IDJkCmRmMXMubWRzMiA8LSBtZXRhTURTKGRmMXMuYmMsaz0yLGF1dG90cmFuc2Zvcm09RkFMU0UsdHJ5PTQwLHRyeW1heD04MCxtYXhpdD0yMDApCnN0cmVzc3Bsb3QoZGYxcy5tZHMyLCBtYWluPSJTaGVwYXJkIHBsb3QiKQpkZjFzLm1kczIKYGBgCgoKPjNEIG1vZGVsIGZpdHMgYmV0dGVyIHRoYW4gMkQuIFN0cmVzcyBmb3IgMkQgYWJvdmUgMC4yCgo+IFN0YXJ0IHdpdGggcGxvdHMgd2hlcmUgc3ltYm9sIGNvbG91ciBpbmRpY2F0ZXMgbGV2ZWxzIG9mIG9uZSBvZiB0aGUgZmFjdG9ycwoKYGBge3J9CmE8LWFzLmRhdGEuZnJhbWUoc2NvcmVzKGRmMXMubWRzMykpCmE8LWNiaW5kKGRmW2MoMTo0KV0sYSkgICAjQWRkIHNpdGUgbmFtZXMgJiBzeW1ib2xzIGZyb20gb3JpZ2luYWwgZGF0YSBmaWxlCnAxPC1nZ3Bsb3QoZGF0YT1hLCBhZXMoeD1OTURTMSwgeT1OTURTMiwgY29sb3I9SElWKSApKwogIGdlb21fcG9pbnQoKSsKICBzdGF0X2VsbGlwc2UoKSsKICBsYWJzKHk9Ik1EUzIiLCB4PSJNRFMxIikrCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcz1jKDE2LDE3KSwKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPQogICAgICAgICAgICAgICAgICAgICAgICAgZ3VpZGVfbGVnZW5kKGxhYmVsLnRoZW1lID0gZWxlbWVudF90ZXh0KHNpemU9NiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlPU5VTEwpCiAgICAgICAgICAgICAgICAgICAgICkKcDI8LWdncGxvdChkYXRhPWEsIGFlcyh4PU5NRFMxLCB5PU5NRFMzLCBjb2xvciA9IEhJVikgKSsKICBnZW9tX3BvaW50KCkrCiAgc3RhdF9lbGxpcHNlKCkrCiAgbGFicyh5PSJNRFMzIiwgeD0iTURTMSIpKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygxNiwxNyksCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0KICAgICAgICAgICAgICAgICAgICAgICAgIGd1aWRlX2xlZ2VuZChsYWJlbC50aGVtZSA9IGVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZT1OVUxMKQogICAgICAgICAgICAgICAgICAgICApCgpwMSArIHAyICsgcGxvdF9sYXlvdXQoZ3VpZGVzPSdjb2xsZWN0JykgKyBwbG90X2Fubm90YXRpb24odGl0bGU9IkhJViBzdGF0dXMiKSAmIHRoZW1lX3FrKCkgJiBzY2FsZV9jb2xvcl91Y2hpY2FnbygpCgpwMTwtZ2dwbG90KGRhdGE9YSwgYWVzKHg9Tk1EUzEsIHk9Tk1EUzIsIGNvbG9yPWNhbmRpZGEpICkrCiAgZ2VvbV9wb2ludCgpKwogIHN0YXRfZWxsaXBzZSgpKwogIGxhYnMoeT0iTURTMiIsIHg9Ik1EUzEiKSsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMTYsMTcpLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9CiAgICAgICAgICAgICAgICAgICAgICAgICBndWlkZV9sZWdlbmQobGFiZWwudGhlbWUgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGU9TlVMTCkKICAgICAgICAgICAgICAgICAgICAgKQpwMjwtZ2dwbG90KGRhdGE9YSwgYWVzKHg9Tk1EUzEsIHk9Tk1EUzMsIGNvbG9yID0gY2FuZGlkYSkgKSsKICBnZW9tX3BvaW50KCkrCiAgc3RhdF9lbGxpcHNlKCkrCiAgbGFicyh5PSJNRFMzIiwgeD0iTURTMSIpKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygxNiwxNyksCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0KICAgICAgICAgICAgICAgICAgICAgICAgIGd1aWRlX2xlZ2VuZChsYWJlbC50aGVtZSA9IGVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZT1OVUxMKQogICAgICAgICAgICAgICAgICAgICApCgpwMSArIHAyICsgcGxvdF9sYXlvdXQoZ3VpZGVzPSdjb2xsZWN0JykgKyBwbG90X2Fubm90YXRpb24odGl0bGU9IkNhbmRpZGEiKSAmIHRoZW1lX3FrKCkgJiBzY2FsZV9jb2xvcl91Y2hpY2FnbygpCgpwMTwtZ2dwbG90KGRhdGE9YSwgYWVzKHg9Tk1EUzEsIHk9Tk1EUzIsIGNvbG9yPWdlbmRlcikgKSsKICBnZW9tX3BvaW50KCkrCiAgc3RhdF9lbGxpcHNlKCkrCiAgbGFicyh5PSJNRFMyIiwgeD0iTURTMSIpKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygxNiwxNyksCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0KICAgICAgICAgICAgICAgICAgICAgICAgIGd1aWRlX2xlZ2VuZChsYWJlbC50aGVtZSA9IGVsZW1lbnRfdGV4dChzaXplPTYpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZT1OVUxMKQogICAgICAgICAgICAgICAgICAgICApCnAyPC1nZ3Bsb3QoZGF0YT1hLCBhZXMoeD1OTURTMSwgeT1OTURTMywgY29sb3IgPSBnZW5kZXIpICkrCiAgZ2VvbV9wb2ludCgpKwogIHN0YXRfZWxsaXBzZSgpKwogIGxhYnMoeT0iTURTMyIsIHg9Ik1EUzEiKSsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMTYsMTcpLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9CiAgICAgICAgICAgICAgICAgICAgICAgICBndWlkZV9sZWdlbmQobGFiZWwudGhlbWUgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGU9TlVMTCkKICAgICAgICAgICAgICAgICAgICAgKQoKcDEgKyBwMiArIHBsb3RfbGF5b3V0KGd1aWRlcz0nY29sbGVjdCcpICsgcGxvdF9hbm5vdGF0aW9uKHRpdGxlPSJTZXgiKSAmIHRoZW1lX3FrKCkgJiBzY2FsZV9jb2xvcl91Y2hpY2FnbygpCgpwMTwtZ2dwbG90KGRhdGE9YSwgYWVzKHg9Tk1EUzEsIHk9Tk1EUzIsIGNvbG9yPXNtb2tpbmdfY3VycmVudCkgKSsKICBnZW9tX3BvaW50KCkrCiAgc3RhdF9lbGxpcHNlKCkrCiAgbGFicyh5PSJNRFMyIiwgeD0iTURTMSIpKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygxNiwxNyksCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0KICAgICAgICAgICAgICAgICAgICAgICAgIGd1aWRlX2xlZ2VuZChsYWJlbC50aGVtZSA9IGVsZW1lbnRfdGV4dChzaXplPTYpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZT1OVUxMKQogICAgICAgICAgICAgICAgICAgICApCnAyPC1nZ3Bsb3QoZGF0YT1hLCBhZXMoeD1OTURTMSwgeT1OTURTMywgY29sb3IgPSBzbW9raW5nX2N1cnJlbnQpICkrCiAgZ2VvbV9wb2ludCgpKwogIHN0YXRfZWxsaXBzZSgpKwogIGxhYnMoeT0iTURTMyIsIHg9Ik1EUzEiKSsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMTYsMTcpLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9CiAgICAgICAgICAgICAgICAgICAgICAgICBndWlkZV9sZWdlbmQobGFiZWwudGhlbWUgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGU9TlVMTCkKICAgICAgICAgICAgICAgICAgICAgKQoKcDEgKyBwMiArIHBsb3RfbGF5b3V0KGd1aWRlcz0nY29sbGVjdCcpICsgcGxvdF9hbm5vdGF0aW9uKHRpdGxlPSJDdXJyZW50IHNtb2tpbmciKSAmIHRoZW1lX3FrKCkgJiBzY2FsZV9jb2xvcl91Y2hpY2FnbygpCgpgYGAKCj5Ucnkgc29tZSB2aXN1YWxpemF0aW9ucyBvZiBwYWlycyBvZiBmYWN0b3JzIHVzaW5nIE1EUzEgJiBNRFMyICh3aGlsZSAzRCBpcyBwcmVmZXJyZWQsIHN0cmVzcyBvZiAzRCBpcyBhcm91bmQgLjE1LCB2cyAwLjIyLCBzbyBub3QgaHVnZSBkaWZmZXJlbmNlKQo+U2VwYXJhdGUgSElWKy8tLCB0aGVuIHVzZSBzeW1ib2wgY29sb3VyIHRvIHNlcGFyYXRlIHNlY29uZCBmYWN0b3IuIAoKYGBge3J9CnAxPC1nZ3Bsb3QoZGF0YT1zdWJzZXQoYSwgY2FuZGlkYT09IlllcyIpLCBhZXMoeD1OTURTMSwgeT1OTURTMiwgY29sb3I9SElWKSApKwogIGdlb21fcG9pbnQoKSsKICBzdGF0X2VsbGlwc2UoKSsKICBsYWJzKHk9Ik1EUzIiLCB4PSJNRFMxIiwKICAgICAgIHRpdGxlPSJDYW5kaWRhIikrCiAgc2NhbGVfc2hhcGVfbWFudWFsKAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9CiAgICAgICAgICAgICAgICAgICAgICAgICBndWlkZV9sZWdlbmQobGFiZWwudGhlbWUgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGU9TlVMTCkKICAgICAgICAgICAgICAgICAgICAgKQpwMjwtZ2dwbG90KGRhdGE9c3Vic2V0KGEsIGNhbmRpZGEgPT0iTm8iKSwgYWVzKHg9Tk1EUzEsIHk9Tk1EUzIsIGNvbG9yID0gSElWKSApKwogIGdlb21fcG9pbnQoKSsKICBzdGF0X2VsbGlwc2UoKSsKICBsYWJzKHk9Ik1EUzIiLCB4PSJNRFMxIiwKICAgICAgIHRpdGxlID0gIk5vIENhbmRpZGEiKSsKICBzY2FsZV9zaGFwZV9tYW51YWwoCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0KICAgICAgICAgICAgICAgICAgICAgICAgIGd1aWRlX2xlZ2VuZChsYWJlbC50aGVtZSA9IGVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZT1OVUxMKQogICAgICAgICAgICAgICAgICAgICApCnBfY29tYmluZWQgPC0gcDEgKyBwMiArIHBsb3RfbGF5b3V0KGd1aWRlcz0nY29sbGVjdCcpICYgdGhlbWVfcWsoKSAmIHNjYWxlX2NvbG9yX3VjaGljYWdvKCkKcF9yYW5nZXNfeCA8LSBjKGdncGxvdF9idWlsZChwX2NvbWJpbmVkW1sxXV0pJGxheW91dCRwYW5lbF9zY2FsZXNfeFtbMV1dJHJhbmdlJHJhbmdlLAogIGdncGxvdF9idWlsZChwX2NvbWJpbmVkW1syXV0pJGxheW91dCRwYW5lbF9zY2FsZXNfeFtbMV1dJHJhbmdlJHJhbmdlKQoKcF9yYW5nZXNfeSA8LSBjKGdncGxvdF9idWlsZChwX2NvbWJpbmVkW1sxXV0pJGxheW91dCRwYW5lbF9zY2FsZXNfeVtbMV1dJHJhbmdlJHJhbmdlLAogICAgICAgICAgICAgICAgZ2dwbG90X2J1aWxkKHBfY29tYmluZWRbWzJdXSkkbGF5b3V0JHBhbmVsX3NjYWxlc195W1sxXV0kcmFuZ2UkcmFuZ2UpCnBfY29tYmluZWQgJiAKICB4bGltKG1pbihwX3Jhbmdlc194KSwgbWF4KHBfcmFuZ2VzX3gpKSAmIAogIHlsaW0obWluKHBfcmFuZ2VzX3kpLCBtYXgocF9yYW5nZXNfeSkpCmBgYAoKYGBge3J9CnAxPC1nZ3Bsb3QoZGF0YT1zdWJzZXQoYSwgSElWPT0iWWVzIiksIGFlcyh4PU5NRFMxLCB5PU5NRFMyLCBjb2xvcj1jYW5kaWRhKSApKwogIGdlb21fcG9pbnQoKSsKICBzdGF0X2VsbGlwc2UoKSsKICBsYWJzKHk9Ik1EUzIiLCB4PSJNRFMxIiwKICAgICAgIHRpdGxlPSJISVYrIikrCiAgc2NhbGVfc2hhcGVfbWFudWFsKAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9CiAgICAgICAgICAgICAgICAgICAgICAgICBndWlkZV9sZWdlbmQobGFiZWwudGhlbWUgPSBlbGVtZW50X3RleHQoc2l6ZT02KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGU9TlVMTCkKICAgICAgICAgICAgICAgICAgICAgKQpwMjwtZ2dwbG90KGRhdGE9c3Vic2V0KGEsIEhJViA9PSJObyIpLCBhZXMoeD1OTURTMSwgeT1OTURTMiwgY29sb3IgPSBjYW5kaWRhKSApKwogIGdlb21fcG9pbnQoKSsKICBzdGF0X2VsbGlwc2UoKSsKICBsYWJzKHk9Ik1EUzIiLCB4PSJNRFMxIiwKICAgICAgIHRpdGxlID0gIkhJVi0iKSsKICBzY2FsZV9zaGFwZV9tYW51YWwoCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0KICAgICAgICAgICAgICAgICAgICAgICAgIGd1aWRlX2xlZ2VuZChsYWJlbC50aGVtZSA9IGVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZT1OVUxMKQogICAgICAgICAgICAgICAgICAgICApCnBfY29tYmluZWQgPC0gcDEgKyBwMiArIHBsb3RfbGF5b3V0KGd1aWRlcz0nY29sbGVjdCcpICYgdGhlbWVfcWsoKSAmIHNjYWxlX2NvbG9yX3VjaGljYWdvKCkKcF9yYW5nZXNfeCA8LSBjKGdncGxvdF9idWlsZChwX2NvbWJpbmVkW1sxXV0pJGxheW91dCRwYW5lbF9zY2FsZXNfeFtbMV1dJHJhbmdlJHJhbmdlLAogIGdncGxvdF9idWlsZChwX2NvbWJpbmVkW1syXV0pJGxheW91dCRwYW5lbF9zY2FsZXNfeFtbMV1dJHJhbmdlJHJhbmdlKQoKcF9yYW5nZXNfeSA8LSBjKGdncGxvdF9idWlsZChwX2NvbWJpbmVkW1sxXV0pJGxheW91dCRwYW5lbF9zY2FsZXNfeVtbMV1dJHJhbmdlJHJhbmdlLAogICAgICAgICAgICAgICAgZ2dwbG90X2J1aWxkKHBfY29tYmluZWRbWzJdXSkkbGF5b3V0JHBhbmVsX3NjYWxlc195W1sxXV0kcmFuZ2UkcmFuZ2UpCnBfY29tYmluZWQgJiAKICB4bGltKG1pbihwX3Jhbmdlc194KSwgbWF4KHBfcmFuZ2VzX3gpKSAmIAogIHlsaW0obWluKHBfcmFuZ2VzX3kpLCBtYXgocF9yYW5nZXNfeSkpCmBgYAoKYGBge3J9CnAxPC1nZ3Bsb3QoZGF0YT1zdWJzZXQoYSwgSElWPT0iWWVzIiksIGFlcyh4PU5NRFMxLCB5PU5NRFMyLCBjb2xvciA9IHNtb2tpbmdfY3VycmVudCkgKSsKICBnZW9tX3BvaW50KCkrCiAgc3RhdF9lbGxpcHNlKCkrCiAgbGFicyh5PSJNRFMyIiwgeD0iTURTMSIsCiAgICAgICB0aXRsZT0iSElWKyIpKwogIHNjYWxlX3NoYXBlX21hbnVhbCgKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPQogICAgICAgICAgICAgICAgICAgICAgICAgZ3VpZGVfbGVnZW5kKGxhYmVsLnRoZW1lID0gZWxlbWVudF90ZXh0KHNpemU9NiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlPU5VTEwpCiAgICAgICAgICAgICAgICAgICAgICkKcDI8LWdncGxvdChkYXRhPXN1YnNldChhLCBISVYgPT0iTm8iKSwgYWVzKHg9Tk1EUzEsIHk9Tk1EUzIsIGNvbG9yID0gc21va2luZ19jdXJyZW50KSApKwogIGdlb21fcG9pbnQoKSsKICBzdGF0X2VsbGlwc2UoKSsKICBsYWJzKHk9Ik1EUzIiLCB4PSJNRFMxIiwKICAgICAgIHRpdGxlID0gIkhJVi0iKSsKICBzY2FsZV9zaGFwZV9tYW51YWwoCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0KICAgICAgICAgICAgICAgICAgICAgICAgIGd1aWRlX2xlZ2VuZChsYWJlbC50aGVtZSA9IGVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZT1OVUxMKQogICAgICAgICAgICAgICAgICAgICApCnBfY29tYmluZWQgPC0gcDEgKyBwMiArIHBsb3RfbGF5b3V0KGd1aWRlcz0nY29sbGVjdCcpICYgdGhlbWVfcWsoKSAmIHNjYWxlX2NvbG9yX3VjaGljYWdvKCkKcF9yYW5nZXNfeCA8LSBjKGdncGxvdF9idWlsZChwX2NvbWJpbmVkW1sxXV0pJGxheW91dCRwYW5lbF9zY2FsZXNfeFtbMV1dJHJhbmdlJHJhbmdlLAogIGdncGxvdF9idWlsZChwX2NvbWJpbmVkW1syXV0pJGxheW91dCRwYW5lbF9zY2FsZXNfeFtbMV1dJHJhbmdlJHJhbmdlKQoKcF9yYW5nZXNfeSA8LSBjKGdncGxvdF9idWlsZChwX2NvbWJpbmVkW1sxXV0pJGxheW91dCRwYW5lbF9zY2FsZXNfeVtbMV1dJHJhbmdlJHJhbmdlLAogICAgICAgICAgICAgICAgZ2dwbG90X2J1aWxkKHBfY29tYmluZWRbWzJdXSkkbGF5b3V0JHBhbmVsX3NjYWxlc195W1sxXV0kcmFuZ2UkcmFuZ2UpCnBfY29tYmluZWQgJiAKICB4bGltKG1pbihwX3Jhbmdlc194KSwgbWF4KHBfcmFuZ2VzX3gpKSAmIAogIHlsaW0obWluKHBfcmFuZ2VzX3kpLCBtYXgocF9yYW5nZXNfeSkpCmBgYAoKCiMjIFJlZmVyZW5jZXMK